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 Ints à Strings. 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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top