在 scala 中翻译具有多个单元的 for 表达式是如何的



我正在阅读"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,并在页面上搜索flatMapList[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]

最新更新