我正在阅读" Scala编程第2版"我从哈克塞尔的课程中了解了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;
^
那么第一个例子的神奇之处是什么?
答案 0 :(得分:8)
[...]
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]
子类型。类型Int => List[Something]
的函数可以替换,因为R
的结果Function1
的协方差,定义为:trait Function1[-T1, +R]
。
Option[A]
不是GenTraversableOnce[A]
,但Option's companion object: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]
。