2013-02-24 17 views
9

Sto leggendo "Programming in Scala 2nd Edition" e ho qualche idea su Monad di un corso Haskell che ho seguito. Comunque, io non capisco perché il seguente codice "magicamente" funziona:Come si traduce un'espressione con più monadi tradotte in scala?

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) 

Non capisco quanto sopra perché secondo del libro Capitolo 23.4, l'espressione for è tradotto in qualcosa di simile:

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

Sono perplesso perché il codice sopra compila perché y => a map (x => x) è di tipo Int => Option[Int], mentre lo b.flatMap prevede uno Int => List[Something].

D'altra parte, il seguente codice non viene compilato (che è un bene altrimenti sarei più perso):

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

Allora, qual è magico con il primo esempio?

risposta

8

[& hellip;] b.flatMap si aspetta uno Int => List[Something].

Non è vero: quello che si aspetta è un Int => GenTraversableOnce[Something]. (Vedere http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.List e cercare la pagina per flatMap.) List[A] è un sottotipo di GenTraversableOnce[A] per ereditarietà. Una funzione di tipo Int => List[Something] può essere sostituita a causa della covarianza del risultato R di Function1, che è definita come: trait Function1[-T1, +R].

Option[A] non è un GenTraversableOnce[A], ma esiste una conversione implicita in Option's companion object: implicit def option2Iterable[A](xo: Option[A]): Iterable[A]. Iterable[A] è un sottotipo di GenTraversableOnce[A]. Così la for-espressione otterrà ampliato per

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

D'altra parte, il seguente codice non viene compilato [& hellip;]

Questo perché a.flatMap, al contrario, è più specifica : richiede davvero un Int => Option[Something]. (Vedere http://www.scala-lang.org/api/current/index.html#scala.Option e cercare la pagina per flatMap.) Questo ha senso, dal momento che un Option[Something] può contenere solo un valore, quindi non è possibile appiattire un arbitrario GenTraversableOnce[Something] in esso. L'unica cosa che può essere appiattita con successo in un Option[Something] è un altro Option[Something].

+0

'Option' non è un' GenTraversableOnce' –

+0

Esiste una conversione implicita denominata option2Iterable definita in oggetto Option, che può convertire Option in Iterable. – Eastsun

+0

@LuigiPlinge: Sì, lo è. Ho aggiornato la risposta per spiegare come funziona. – ruakh

Problemi correlati