9

我正在阅读“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)是 type Int => Option[Int],而b.flatMap期望 a 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;
                          ^

那么第一个例子有什么神奇之处呢?

4

1 回答 1

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]可以被替换,其定义为:。RFunction1trait Function1[-T1, +R]

Option[A]不是,但Option 的伴随对象GenTraversableOnce[A]中存在隐式转换: 。是 的子类型。所以 for 表达式将扩展为implicit def option2Iterable[A](xo: Option[A]): Iterable[A]Iterable[A]GenTraversableOnce[A]

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。)这是有道理的,因为 anOption[Something]只能保存一个值,所以你不能将任意GenTraversableOnce[Something]内容展平。唯一可以成功扁平化为 an 的Option[Something]是 another Option[Something]

于 2013-02-24T03:23:04.830 回答