这是this的后续问题。帮我理解这个Scala代码:scalaz IO Monad和implicits
这里是我想了解(这是从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,所以它需要定义scalaz.Monad
特征的pure
和bind
抽象值。
pure
获取一个值并将其转换为“容器”类型中包含的值。例如,它可能需要Int
并返回List[Int]
。这似乎很简单。
bind
需要一个“容器”类型和一个将容器容纳的类型映射到另一个类型的函数。返回的值是相同的容器类型,但它现在保存一个新类型。一个例子是采用List[Int]
并使用映射Int
s到String
s的函数将其映射到List[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]
,并使用一个函数,它的A
,并返回一个IO[B]
它映射到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
解析为容器类型?
Scalaz实际开箱提供了一个IO单子了。进口scalaz.effects._ – Apocalisp