Pregunta

Este es un seguimiento de este pregunta.

Aquí está el código que estoy tratando de entender (es de http://apocalisp.wordpress.com/2010/10/17/scalaz-tutorial-enumeration basado--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)()
    }
  }
}

Este código se usa así (supongo que un import io._ está implícito)

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))

Ahora estoy tratando de entender el implicit val IOMonad definición. Así es como lo entiendo. Esto es un Scalaz.monad, por lo que necesita definir pure y bind valores abstractos del scalaz.Monad rasgo.

pure toma un valor y lo convierte en un valor contenido en el tipo de "contenedor". Por ejemplo, podría tomar un Int y devolver un List[Int]. Esto parece bastante simple.

bind Toma un tipo de "contenedor" y una función que mapea el tipo que el contenedor mantiene a otro tipo. El valor que se devuelve es el mismo tipo de contenedor, pero ahora está conteniendo un nuevo tipo. Un ejemplo sería tomar un List[Int] y mapearlo a un List[String] Usando una función que mapea Ints para Strings. Es bind más o menos lo mismo que map?

La implementación de bind es donde estoy atascado. Aquí está el código:

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)()
}

Esta definición toma IO[A] y lo mapea para IO[B] usando una función que toma una A y devuelve un IO[B]. Supongo que para hacer esto, tiene que usar flatMap para "aplanar" el resultado (¿correcto?).

los = IO { ... } es lo mismo que

 = new IO[A] {
  def unsafePerformIO = implicitly[Monad[Function0]].bind(() => a.unsafePerformIO,
      (x:A) => () => f(x).unsafePerformIO)()
  }
}

¿Pienso?

la implicitly El método busca un valor implícito (valor, ¿verdad?) Que implementa Monad[Function0]. ¿De dónde viene esta definición implícita? Supongo que esto es del implicit val IOMonad = new Monad[IO] {...} Definición, pero estamos dentro de esa definición en este momento y las cosas se vuelven un poco circulares y mi cerebro comienza a atascarse en un bucle infinito :)

Además, el primer argumento a bind (() => a.unsafePerformIO) parece ser una función que no toma parámetros y devuelve a.unsafeperformio. ¿Cómo debo leer esto? bind toma un tipo de contenedor como su primer argumento, así que tal vez () => a.unsafePerformIO ¿Se resuelve a un tipo de contenedor?

No hay solución correcta

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top