Помогите мне понять этот код Scala: скалаз IO Monad и последствия
Это продолжение кэто вопрос.
Вот код, который я пытаюсь понять (это от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))
Я сейчас пытаюсь понятьimplicit val IOMonad
определение. Вот как я это понимаю. Этоscalaz.Monadтак что нужно определитьpure
а такжеbind
абстрактные значенияscalaz.Monad
черта характера.
pure
принимает значение и превращает его в значение, содержащееся в типе «контейнер». Например, это может занятьInt
и вернутьList[Int]
, Это кажется довольно простым.
bind
принимает тип «контейнер» и функцию, которая отображает тип, который контейнер содержит, на другой тип. Возвращаемое значение имеет тот же тип контейнера, но теперь оно содержит новый тип. Примером будет взятьList[Int]
и сопоставление его сList[String]
используя функцию, которая отображаетInt
сString
s. Является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)()
}
}
Думаю?
implicitly
Метод ищет неявное значение (значение, верно?), которое реализуетMonad[Function0]
, Откуда это неявное определение? Я предполагаю, что это изimplicit val IOMonad = new Monad[IO] {...}
определение, но мы находимся внутри этого определения прямо сейчас, и все становится немного круглым, и мой мозг начинает застревать в бесконечном цикле :)
Кроме того, первый аргументbind
(() => a.unsafePerformIO
) представляется функцией, которая не принимает параметров и возвращает a.unsafePerformIO. Как мне это прочитать?bind
принимает тип контейнера в качестве первого аргумента, так что, возможно,() => a.unsafePerformIO
разрешается к типу контейнера?