Ayúdame a entender este código de Scala: SCALAZ IO Mónada e Implicits
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 Int
s para String
s. 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