以下是我试图理解的代码(来自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))
让我们从bufferFile
定义开始。我是否认为io.IO的apply
方法被称为正确? apply
方法采用无参数函数返回一个值(正确吗?)。我想这就是我被困住的地方。有人可以解释bufferFile
的定义是如何工作的吗?
答案 0 :(得分:5)
是的,你是对的,差不多;使用所谓的“按名称”参数调用io.IO.apply
,该参数基本上是一个不带任何东西(Unit
)并返回A
的函数。很酷的是,当您直接传递A
的{{1}}实例时,它会被转换为类似new BufferedReader(new FileReader(f))
的内容。
作为() => new BufferedReader(new FileReader(f))
的结果,您获得了apply
的实例,该实例定义了一个方法IO[BufferedReader]
,该方法只返回捕获的def unsafePerformIO
的实例。
答案 1 :(得分:2)
补充agilesteel的answer代码
def bufferFile(f: File) = IO { new BufferedReader(new FileReader(f)) }
相当于
def bufferFile(f: File) = new IO[A] {
def unsafePerformIO = { new BufferedReader(new FileReader(f)) }
}