2013-02-24 11 views
9

Czytam "Programowanie w Scala 2nd Edition" i mam pewne pojęcie o monadzie z kursu Haskella, który zrobiłem. Jednak nie rozumiem, dlaczego następujący kod „magicznie” działa:W jaki sposób na wyrażenie z wieloma monadami tłumaczone jest słowo 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) 

Nie rozumiem powyższe ponieważ według książki rozdziale 23.4, wyrażenie for jest tłumaczona na coś takiego:

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

Jestem zaskoczony, dlaczego powyższy kod się kompiluje, ponieważ y => a map (x => x) jest typu Int => Option[Int], podczas gdy b.flatMap oczekuje Int => List[Something].

Z drugiej strony, następujący kod NIE kompilować (co jest dobre, inaczej byłbym bardziej zagubiony):

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

Więc co jest magiczne z pierwszego przykładu?

Odpowiedz

8

[& hellip;] b.flatMap spodziewa się Int => List[Something].

To nie jest prawda: to, czego oczekuje, to Int => GenTraversableOnce[Something]. (Patrz http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.List i wyszukaj na stronie flatMap.) List[A] jest podtypem GenTraversableOnce[A] według dziedziczenia. Funkcja typu Int => List[Something] może być zastąpiona z powodu kowariancji wyniku R z Function1, który jest zdefiniowany jako: trait Function1[-T1, +R].

Option[A] nie jest GenTraversableOnce[A], ale istnieje niejawna konwersja w Option's companion object: implicit def option2Iterable[A](xo: Option[A]): Iterable[A]. Iterable[A] jest podtypem GenTraversableOnce[A]. Więc za wyrażenie dostanie rozszerzony

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

Z drugiej strony, następujący kod NIE kompilować [& hellip;]

To dlatego a.flatMap, przeciwnie, jest bardziej szczegółowa : to naprawdę wymaga Int => Option[Something]. (Patrz http://www.scala-lang.org/api/current/index.html#scala.Option i wyszukaj na stronie pod adresem flatMap). Ma to sens, ponieważ Option[Something] może zawierać tylko jedną wartość, więc nie można spłaszczyć do niej arbitralnego GenTraversableOnce[Something]. Jedyną rzeczą, która może z powodzeniem zostać spłaszczona w postaci Option[Something], jest inna Option[Something].

+0

'Opcja' nie jest' GenTraversableOnce' –

+0

Istnieje niejawna konwersja nazwana opcja2Iterowalna zdefiniowana w obiekcie Option, która może zmienić opcję na Iterable. – Eastsun

+0

@LuigiPlinge: Tak, jest. Zaktualizowałem odpowiedź, aby wyjaśnić, jak to działa. – ruakh

Powiązane problemy