2013-08-18 38 views
2

我正在使用scalaz 6.0和scala。我使用迭代從輸入流中讀取。來自標準IO的Iteratee輸入

這裏是我簡單的叫做simple.txt的文件。



測試

我iteratee將建立一個IO單子打印線

def printLines: IterV[String, IO[Unit]] = { 
    def step(currentIO: IO[Unit])(input: Input[String]): IterV[String, IO[Unit]] = 
    input match { 
     case El(x) => Cont(
      step(
       currentIO.flatMap(_ => putStrLn(x)) 
     ) 
    ) 
     case IterV.Empty() => Cont(step(currentIO)) 
     case EOF() => Done(currentIO, EOF[String]) 
    } 
    Cont(step(io())) 
} 

當我使用enumeratorM

getFileLines(new File(".../simple.txt"))(printLines).flatMap(_.run).unsafePerformIO 

我檢索正確的輸出。

當我嘗試使用

getLines(printLines).flatMap(_.run).unsafePerformIO 

我只得到「這」回控制檯。 getLines使用標準輸入流。我已經爲iteratee添加了調試語句,並且getLines似乎在第一行後發送EOF(),但我無法解決它。

回答

2

這是getReaderLines定義中的一個錯誤。比較當前版本:

/** Enumerate the lines from a BufferedReader */ 
def getReaderLines(r: => BufferedReader): EnumeratorM[IO, String] = 
    new EnumeratorM[IO, String] { 
    def apply[A](it: IterV[String, A]) = { 
     def loop(i: IterV[String, A]): IO[IterV[String, A]] = i.fold(
     done = (_,_) => io { i }, 
     cont = k => for { 
      s <- rReadLn(r) 
      a <- s.map(l => loop(k(El(l)))).getOrElse(io(i)) 
     } yield a 
    ) 
     loop(it) 
    } 
    } 

有了一個工程:

/** Enumerate the lines from a BufferedReader */ 
def getReaderLines(r: => BufferedReader): EnumeratorM[IO, String] = 
    new EnumeratorM[IO, String] { 
    lazy val reader = r 

    def apply[A](it: IterV[String, A]) = { 
     def loop(i: IterV[String, A]): IO[IterV[String, A]] = i.fold(
     done = (_,_) => io { i }, 
     cont = k => for { 
      s <- rReadLn(reader) 
      a <- s.map(l => loop(k(El(l)))).getOrElse(io(i)) 
     } yield a 
    ) 
     loop(it) 
    } 
    } 

問題是r是按名稱參數,這意味着考慮到getLines的定義方式,當前版本在每個循環中創建一個新的包裝標準輸入的閱讀器。

在此之前被固定在庫(我懷疑還會有多大的急於得到6.0.5出了門),最簡單的解決方法是寫自己的getLines

val getLines: EnumeratorM[IO, String] = { 
    val r = new BufferedReader(new InputStreamReader(System.in)) 
    getReaderLines(r) 
} 

這將按預期工作。