Помогите мне понять этот код Scala: scalaz IO Monad и implits

Это продолжение этого вопроса.

Вот код, который я пытаюсь понять (он взят из http://apocalisp.wordpress.com/2010/10/17/scalaz-tutorial-enumeration-based-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)()
    }
  }
}

Этот код используется следующим образом (я предполагаю, что подразумевается import io ._ )

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

Теперь я пытаюсь понять неявный неявный val IOMonad определение. Вот как я это понимаю. Это scalaz.Monad , поэтому ему необходимо определить pure и привязать абстрактные значения черты scalaz.Monad .

pure принимает значение и превращает его в значение, содержащееся в типе «контейнер». Например, он может взять Int и вернуть List [Int] . Это кажется довольно простым.

bind принимает тип «контейнера» и функцию, которая сопоставляет тип, который хранится в контейнере, с другим типом. Возвращаемое значение является контейнером того же типа, но теперь содержит новый тип. В качестве примера можно взять List [Int] и сопоставить его с List [String] с помощью функции, которая отображает Int s в String с. bind почти то же самое, что map ?

Реализация bind - вот где я застрял. Вот код:

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

Это определение принимает IO [A] и сопоставляет его с IO [B] с помощью функции, которая принимает A и возвращает IO [B] . Я предполагаю, что для этого он должен использовать flatMap , чтобы «сгладить» результат (правильно?).

= IO {...} то же самое, что

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

, я думаю?

метод неявно ищет неявное значение (значение, верно?) который реализует Монаду [Function0] . Откуда взялось это неявное определение? Я предполагаю, что это из определения implicit val IOMonad = new Monad [IO] {...} , но мы сейчас внутри этого определения, и все становится немного круговым, и мой мозг начинает застряли в бесконечном цикле :)

Кроме того, первый аргумент bind ( () => a.unsafePerformIO ) кажется функцией, которая не принимает параметров и возвращает a.unsafePerformIO. Как мне это прочитать? bind принимает тип контейнера в качестве первого аргумента, поэтому, возможно, () => a.unsafePerformIO преобразуется в тип контейнера?

5
задан Community 23 May 2017 в 11:58
поделиться