Aiutami a capire questo codice Scala: Scalaz Io Monad e implica
Domanda
Questo è un seguito a questo domanda.
Ecco il codice che sto cercando di capire (viene da http://apocalisp.wordpress.com/2010/10/17/scalaz-tutorial-enumeration bond-io-with-iteratees/):
object io {
sealed trait IO[A] {
def unsafePerformIO: A
}
object IO {
def apply[A](a: => A): IO[A] = new IO[A] {
def unsafePerformIO = a
}
}
implicit val IOMonad = new Monad[IO] {
def pure[A](a: => A): IO[A] = IO(a)
def bind[A,B](a: IO[A], f: A => IO[B]): IO[B] = IO {
implicitly[Monad[Function0]].bind(() => a.unsafePerformIO,
(x:A) => () => f(x).unsafePerformIO)()
}
}
}
Questo codice è usato in questo modo (sto assumendo un import io._
è implicito)
def bufferFile(f: File) = IO { new BufferedReader(new FileReader(f)) }
def closeReader(r: Reader) = IO { r.close }
def bracket[A,B,C](init: IO[A], fin: A => IO[B], body: A => IO[C]): IO[C] = for { a <- init
c <- body(a)
_ <- fin(a) } yield c
def enumFile[A](f: File, i: IterV[String, A]): IO[IterV[String, A]] = bracket(bufferFile(f),
closeReader(_:BufferedReader),
enumReader(_:BufferedReader, i))
Ora sto cercando di capire il implicit val IOMonad
definizione. Ecco come lo capisco. Questo è un Scalaz.Monad, quindi deve definire pure
e bind
valori astratti del scalaz.Monad
tratto.
pure
Prende un valore e lo trasforma in un valore contenuto nel tipo "contenitore". Per esempio potrebbe richiedere un Int
e restituire a List[Int]
. Questo sembra piuttosto semplice.
bind
Prende un tipo di "contenitore" e una funzione che mappa il tipo che il contenitore tiene su un altro tipo. Il valore che viene restituito è lo stesso tipo di contenitore, ma ora ha un nuovo tipo. Un esempio sarebbe prendere un List[Int]
e mappandolo a a List[String]
usando una funzione che mappe Int
s a String
S. È bind
praticamente lo stesso di map
?
L'implementazione di bind
è dove sono bloccato. Ecco il codice:
def bind[A,B](a: IO[A], f: A => IO[B]): IO[B] = IO {
implicitly[Monad[Function0]].bind(() => a.unsafePerformIO,
(x:A) => () => f(x).unsafePerformIO)()
}
Questa definizione prende IO[A]
e mappure a IO[B]
usando una funzione che richiede un A
e restituisce un IO[B]
. Immagino di farlo, deve usare flatMap
"appiattire" il risultato (corretto?).
Il = IO { ... }
equivale a
= new IO[A] {
def unsafePerformIO = implicitly[Monad[Function0]].bind(() => a.unsafePerformIO,
(x:A) => () => f(x).unsafePerformIO)()
}
}
Penso?
il implicitly
Il metodo cerca un valore implicito (valore, giusto?) che implementa Monad[Function0]
. Da dove viene questa definizione implicita? Immagino che questo provenga dal implicit val IOMonad = new Monad[IO] {...}
Definizione, ma siamo dentro quella definizione in questo momento e le cose diventano un po 'circolari e il mio cervello inizia a rimanere bloccato in un ciclo infinito :)
Inoltre, il primo argomento a bind
(() => a.unsafePerformIO
) sembra essere una funzione che non assume parametri e restituisce A.UnsafePerformi. Come dovrei leggere questo? bind
prende un tipo di contenitore come primo argomento, quindi forse () => a.unsafePerformIO
si risolve a un tipo di contenitore?
Nessuna soluzione corretta