Aidez-moi à comprendre ce code scala: Scalaz io monad et implicits
Question
Ceci est un suivi de cette question.
Voici le code que j'essaie de comprendre (c'est de http://apocalisp.wordpress.com/2010/10/17/scalaz-tutorial-enumeration-basez-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)()
}
}
}
Ce code est utilisé comme ça (je suppose qu'un import io._
est implicite)
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))
J'essaye maintenant de comprendre le implicit val IOMonad
définition. Voici comment je le comprends. C'est un scalaz.monad, il doit donc définir pure
et bind
valeurs abstraites du scalaz.Monad
caractéristique.
pure
Prend une valeur et le transforme en valeur contenue dans le type "conteneur". Par exemple, cela pourrait prendre un Int
et retourner un List[Int]
. Cela semble assez simple.
bind
Prend un type "conteneur" et une fonction qui mappe le type que le conteneur contient à un autre type. La valeur renvoyée est le même type de conteneur, mais il tient maintenant un nouveau type. Un exemple serait de prendre un List[Int]
et le cartographier à un List[String]
en utilisant une fonction qui mappe Int
s à String
s. Est bind
à peu près la même chose que map
?
L'implémentation de bind
c'est là que je suis coincé. Voici le code:
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)()
}
Cette définition prend IO[A]
et le mappe à IO[B]
en utilisant une fonction qui prend un A
et renvoie un IO[B]
. Je suppose que pour le faire, il doit utiliser flatMap
pour «aplatir» le résultat (correct?).
La = IO { ... }
est le même que
= new IO[A] {
def unsafePerformIO = implicitly[Monad[Function0]].bind(() => a.unsafePerformIO,
(x:A) => () => f(x).unsafePerformIO)()
}
}
Je pense?
la implicitly
La méthode recherche une valeur implicite (valeur, non?) qui implémente Monad[Function0]
. D'où vient cette définition implicite? Je suppose que c'est du implicit val IOMonad = new Monad[IO] {...}
Définition, mais nous sommes à l'intérieur de cette définition en ce moment et les choses deviennent un peu circulaires et mon cerveau commence à rester coincé dans une boucle infinie :)
Aussi, le premier argument à bind
(() => a.unsafePerformIO
) semble être une fonction qui ne prend aucun paramètre et renvoie a.unsafeperformrio. Comment dois-je lire ceci? bind
prend un type de conteneur comme premier argument, alors peut-être () => a.unsafePerformIO
se résout en un type de conteneur?
Pas de solution correcte