> scala> val foos = List(Foo(List(Bar(Some(List(Baz(List(new Blargh))))))))
> foos: List[Foo] = List(Foo(List(Bar(Some(List(Baz(List(Blargh@14bcb102))))))))
>
>
> scala> for {
> | foo <- foos
> | bar <- foo.bars
> | bazs <- bar.bazs
> | baz <- bazs
> | blargh <- baz.blarghs
> | } yield blargh
> <console>:32: error: type mismatch;
> found : List[Blargh]
> required: Option[?]
> baz <- bazs
I managed to extract a reduced example:
This compiles:
def x : List[Option[Int]] = ???
for { y <- x; z <- y } yield z
This does not:
def x : Option[List[Int]] = ???
for { y <- x; z <- y } yield z
I *think* the reason is, that you can always transform an Option into a
List but not vice versa. Lets look at your larger code example and
desugare it:
foos.flatMap { foo =>
foo.bars.flatMap { bar =>
bar.bazs.flatMap { bazs =>
bazs.flatMap { baz =>
baz.blarghs
}
}
}
}
From this you see that the types are determined inside out.
The crucial part is this:
bazs.flatMap { baz =>
baz.blarghs
}
bazs has type Option[List[Blargh]] and from the minimal example above,
this cannot possibly compile, as you cannot convert a List to an Option.
IMO people should not mix container types in for comprehensions. It
reduces type safety and can lead to unexpected behavior especially after
several layers of nesting and especially if types like Set or Map are
involved, which sometimes silently remove some of your duplicates.
Therefore, manually transform your Option to a List and you'll be fine.