Polymerase - 2 months ago 8x
Scala Question

# Why does For Comprehension generator suppress Option type?

In the code below, version 1 gives the correct result. I make a small variation in V2. The None value had disappeared which is Ok as that is how For Expression works. But what is the reason the yield output in V2 no longer respects the data type returned by myList.lift() which is an Option (as in V1)?

``````val myList = List(12, 34, "ABC")
``````

Version 1

``````for { i <- (0 to 3).toList } yield myList.lift(i)
// res1: List[Option[Any]] = List(Some(12), Some(34), Some(ABC), None)
``````

Version 2

``````for {
i <- (0 to 3).toList
x <- myList.lift(i)
} yield x
// res2: List[Any] = List(12, 34, ABC)
``````

Desugaring the first case:

``````// desugar for comprehension:
(0 to 3).toList.map(
i => myList.lift(i))
``````

Desugaring the second case:

``````// desugar for comprehension:
(0 to 3).toList.flatMap(
i => myList.lift(i).map(
x => x))

// remove .map(x => x):
(0 to 3).toList.flatMap(
i => myList.lift(i))

// desugar flatMap:
(0 to 3).toList.map(
i => myList.lift(i)).flatten
``````

The second case simplifies to the first case with a `.flatten` at the end, which explains the difference in the results: `res2 = res1.flatten`.

## What's actually going on?

Scala can treat `Option` as a sequence:

``````Some(foo) --> Seq(foo)
None      --> Seq()
``````

The `.flatten` is just flattening the sequence of sequences.

If you're curious about the types:

• `scala.collection.Seq.flatten` requires that the 'inner' type have an implicit conversion to `GenTraversableOnce[T]`
• there's a global implicit conversion from `Option[T]` to `Iterable[T]`
• `Iterable[T] <: GenTraversableOnce[T]`

## What does <- mean then?

The `<-` in `x <- myList.lift(i)` doesn"t just assign a variable to a value, it "gets a value out of" `myList.lift(i)`. When you "get a value out of" an `Option[T]`, you get `foo` for `Some(foo)` and nothing for `None`. "Getting nothing" means the `yield` doesn"t run at all for a `None`, so nothing shows up in the result for the "iteration" when `i = 3`.

If you're curious about this "get a value out of" concept that is defined for `Seq`, `Option`, and many other types in Scala, it is defined for any Monad.