I am reading "Programming in Scala 2nd Edition" and I have some idea about monad from a Haskell course I took. However, I do not understand why the following code "magically" works:
scala> val a: Option[Int] = Some(100)
a: Option[Int] = Some(100)
scala> val b = List(1, 2, 3)
b: List[Int] = List(1, 2, 3)
for ( y <- b; x <- a ) yield x;
res5: List[Int] = List(100, 100, 100)
I do not understand the above because according to the book's Chapter 23.4, the for
expression is translated to something like:
b flatMap ( y =>
a map ( x => x )
)
I am puzzled why the above code compiles because y => a map (x => x)
is of type Int => Option[Int]
, while the b.flatMap
expects a Int => List[Something]
.
On the other hand, the following code does NOT compile (which is good otherwise I would be more lost):
scala> for ( x <- a; y <- b ) yield y;
<console>:10: error: type mismatch;
found : List[Int]
required: Option[?]
for ( x <- a; y <- b ) yield y;
^
So what is magical with the first example?
[…]
b.flatMap
expects aInt => List[Something]
.
That is not true: what it expects is an Int => GenTraversableOnce[Something]
. (See http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.List, and search the page for flatMap
.) List[A]
is a subtype of GenTraversableOnce[A]
by inheritance. A function of type Int => List[Something]
can be substituded because of the covariance of the result R
of Function1
, which is defined as: trait Function1[-T1, +R]
.
Option[A]
is not a GenTraversableOnce[A]
, but there is an implicit conversion in Option's companion object: implicit def option2Iterable[A](xo: Option[A]): Iterable[A]
. Iterable[A]
is a subtype of GenTraversableOnce[A]
. So the for-expression will get expanded to
b flatMap ( y =>
option2Iterable(a map ( x => x ))
)
On the other hand, the following code does NOT compile […]
This is because a.flatMap
, by contrast, is more specific: it really does require an Int => Option[Something]
. (See http://www.scala-lang.org/api/current/index.html#scala.Option, and search the page for flatMap
.) This makes sense, since an Option[Something]
can only hold one value, so you couldn't flatten an arbitrary GenTraversableOnce[Something]
into it. The only thing that can successfully be flattened into an Option[Something]
is another Option[Something]
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With