如何在scala中翻译多个monad的for表达式?

时间:2013-02-24 03:09:20

标签: scala monads

我正在阅读" 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;
                          ^

那么第一个例子的神奇之处是什么?

1 个答案:

答案 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 objectimplicit 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]