我正在阅读"Programming in Scala 2nd Edition",我从Haskell课程中对monad有一些了解。但是,我不明白为什么以下代码"神奇地"工作:
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)
我不明白以上内容,因为根据本书的第 23.4 章,for
表达式被翻译成类似的东西:
b flatMap ( y =>
a map ( x => x )
)
我很困惑为什么上面的代码会编译,因为y => a map (x => x)
是 Int => Option[Int]
型,而b.flatMap
期望Int => List[Something]
。
另一方面,以下代码无法编译(这很好,否则我会更加迷茫(:
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;
^
那么第一个例子有什么神奇之处呢?
[...]
b.flatMap
期待Int => List[Something]
。
事实并非如此:它期望的是Int => GenTraversableOnce[Something]
。(请参阅 http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.List,并在页面上搜索flatMap
。 List[A]
是遗传GenTraversableOnce[A]
的亚型。由于结果R
的协方差,Function1
的函数可以代Int => List[Something]
,定义为:trait Function1[-T1, +R]
。
Option[A]
不是GenTraversableOnce[A]
,但在 Option 的配套对象中有一个隐式转换:implicit def option2Iterable[A](xo: Option[A]): Iterable[A]
。 Iterable[A]
是GenTraversableOnce[A]
的一个亚型。所以 for-expression 将扩展到
b flatMap ( y =>
option2Iterable(a map ( x => x ))
)
另一方面,以下代码无法编译 [...]
这是因为 相比之下,a.flatMap
更具体:它确实需要Int => Option[Something]
.(请参阅 http://www.scala-lang.org/api/current/index.html#scala.Option,并在页面上搜索flatMap
。这是有道理的,因为Option[Something]
只能保存一个值,因此您无法将任意GenTraversableOnce[Something]
展平到其中。唯一可以成功展平成Option[Something]
的是另一个Option[Something]
。