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 Ints a StringS. È 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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top