2

我正在使用带有 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()))
}

当我使用 enumeratorM

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

我检索到正确的输出。

当我尝试使用

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

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

4

1 回答 1

2

This is a bug in the definition of getReaderLines. Compare the current version:

/** 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)
    }
  }

With one that works:

/** 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)
    }
  }

The issue is that r is a by-name parameter, which means that given the way that getLines is defined, the current version creates a new reader wrapping standard input on every loop.

Until this gets fixed in the library (and I doubt there'll be much of a rush to get 6.0.5 out the door), the simplest fix is to write your own getLines:

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

This will work as expected.

于 2013-08-18T02:28:35.820 回答