2013-02-24 24 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