2011-09-13 52 views
4

這裏是我想了解(這是從http://apocalisp.wordpress.com/2010/10/17/scalaz-tutorial-enumeration-based-io-with-iteratees/)代碼:幫助我理解這個Scala代碼:scalaz IO單子

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的定義是如何工作的嗎?

回答

5

是的,你是對的,差不多; io.IO.apply通過所謂的「by name」參數進行調用,該參數基本上是一個不佔用任何內容的函數(Unit)並返回A。很酷的是,當你直接通過這樣的A實例時,它會被轉換成類似() => new BufferedReader(new FileReader(f))的東西。

作爲apply的結果,您將得到一個IO[BufferedReader]的實例,該實例定義了一個方法def unsafePerformIO,該方法只返回捕獲的BufferedReader的實例。

2

補全agilesteelanswer,代碼

def bufferFile(f: File) = IO { new BufferedReader(new FileReader(f)) } 

是相當於

def bufferFile(f: File) = new IO[A] { 
    def unsafePerformIO = { new BufferedReader(new FileReader(f)) } 
}