来自标准IO的Iteratee输入

时间:2013-08-18 00:04:15

标签: scala stdio scalaz iterate

我正在使用带有scala的scalaz 6.0。我正在使用iteratees从输入流中读取。

这是我所说的简单文件simple.txt。

  

这个   是   测试

我的iteratee会建立一个io monad来打印行

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()))
}

当我使用枚举器M

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

我检索到正确的输出。

当我尝试使用

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

我只将“This”带回控制台。 getLines使用标准输入流。我已经向iteratee添加了调试语句,并且getLines似乎在第一行之后发送了EOF()并且我无法解决它。

1 个答案:

答案 0 :(得分: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)
}

这将按预期工作。