2013-02-24 4 views
9

Ich lese "Programmierung in Scala 2nd Edition" und ich habe eine Idee über Monad von einem Haskell-Kurs, den ich nahm. Aber ich verstehe nicht, warum der folgende Code „magische Weise“ funktioniert:Wie wird ein Ausdruck mit mehreren Monaden in Scala übersetzt?

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) 

Ich verstehe nicht, die oben, weil nach dem Kapitel des Buchs 23,4, der for Ausdruck ist so etwas wie übersetzt:

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

Ich bin verwirrt, warum der obige Code kompiliert, weil y => a map (x => x) vom Typ Int => Option[Int] ist, während die eine Int => List[Something] erwartet.

Auf der anderen Seite, der folgende Code kompiliert nicht (was ich wäre verloren gut anders ist):

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; 
         ^

Also, was mit dem ersten Beispiel ist magisch?

Antwort

8

[& hellip;] b.flatMap erwartet eine Int => List[Something].

Das ist nicht wahr: was es erwartet, ist ein Int => GenTraversableOnce[Something]. (Siehe http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.List, und suchen Sie die Seite nach flatMap.) List[A] ist ein Untertyp von GenTraversableOnce[A] durch Vererbung. Eine Funktion des Typs Int => List[Something] kann aufgrund der Kovarianz des Ergebnisses R von Function1, definiert als trait Function1[-T1, +R], ersetzt werden.

Option[A] ist kein GenTraversableOnce[A], aber es gibt eine implizite Konvertierung in Option's companion object: implicit def option2Iterable[A](xo: Option[A]): Iterable[A]. Iterable[A] ist ein Untertyp von GenTraversableOnce[A]. So ist der für Ausdruck wird

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

Auf der anderen Seite, der folgende Code nicht kompiliert [& hellip;]

Dies liegt daran, a.flatMap, dagegen spezifischere ist : Es erfordert wirklich eine Int => Option[Something]. (Siehe http://www.scala-lang.org/api/current/index.html#scala.Option, und suchen Sie die Seite nach flatMap.) Dies ist sinnvoll, da ein Option[Something] kann nur einen Wert halten, so dass Sie nicht eine beliebige GenTraversableOnce[Something] in es glätten können. Das einzige, was erfolgreich zu einem Option[Something] geglättet werden kann, ist ein weiterer Option[Something].

+0

'Option' ist kein' GenTraversableOnce' –

+0

Es gibt eine im Option -Objekt definierte implizite Konvertierung namens option2Iterable, die Option zu Iterable konvertieren kann. – Eastsun

+0

@LuigiPlinge: Ja, ist es. Ich habe die Antwort aktualisiert, um zu erklären, wie das funktioniert. – ruakh

Verwandte Themen