2013-02-24 27 views
9

我在阅读“Programming in Scala 2nd Edition”,我对从Haskell课程中学到的monad有一些想法。不过,我不明白为什么下面的代码“神奇”的工作原理:如何用scala翻译多个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; 
         ^

那么,什么是神奇与第一例子吗?

回答

8

[&hellip;] 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]的子类型。由于Function1的结果R的协方差,Int => List[Something]类型的函数可以被替代,其被定义为: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]的子类型。因此,对于表达将得到扩大到

b flatMap (y => 
    option2Iterable(a map (x => x)) 
) 

在另一方面,下面的代码无法编译[&hellip;]

这是因为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]

+0

'Option'不是'GenTraversableOnce' – 2013-02-24 03:29:32

+0

在Option对象中定义了一个名为option2Iterable的隐式转换,它可以将Option选项转换为Iterable。 – Eastsun 2013-02-24 03:50:21

+0

@LuigiPlinge:是​​的。我已经更新了答案以解释这是如何工作的。 – ruakh 2013-02-24 04:25:19