Just tried a workaround by manually casting to something which has overloaded flatMap
, which indeed works
class OptionFlatMapIterable[A](o: Option[A]){ self =>
def map[B](f: A => B): Option[B] = o.map(f)
def foreach[B](f: A => B): Unit = o.foreach(f)
def flatMap[B](f: A => Option[B]): Option[B] = o.flatMap(f)
def flatMap[B](f: A => Iterable[B]): Iterable[B] = if (o.isEmpty) Seq.empty else f(o.get)
def filter(p: A => Boolean): Option[A] = o.filter(p)
/** Necessary to keep $option from being implicitly converted to
* [[scala.collection.Iterable]] in `for` comprehensions.
*/
def withFilter(p: A => Boolean): WithFilter = new WithFilter(p)
/** We need a whole WithFilter class to honor the "doesn't create a new
* collection" contract even though it seems unlikely to matter much in a
* collection with max size 1.
*/
class WithFilter(p: A => Boolean) {
def map[B](f: A => B): Option[B] = self filter p map f
def flatMap[B](f: A => Option[B]): Option[B] = self filter p flatMap f
def flatMap[B](f: A => Iterable[B]): Iterable[B] = if (o.isEmpty) Seq.empty else f(o.get)
def foreach[U](f: A => U): Unit = self filter p foreach f
def withFilter(q: A => Boolean): WithFilter = new WithFilter(x => p(x) && q(x))
}
}
new OptionFlatMapIterable(Some(42)).flatMap{ o: Int =>
Seq(o, o + 1, o + 3).map{ i =>
(i,i)
}
}
// res0: Iterable[(Int, Int)] = List((42,42), (43,43), (45,45))
for{
o: Int <- new OptionFlatMapIterable(Some(42))
i <- Seq(o, o + 1, o + 3)
} yield (o, i)
// res1: Iterable[(Int, Int)] = List((42,42), (42,43), (42,45))
however the type inference is not working satisfactorily… the o: Int
type annotation is indeed necessary for this to compile…