我正在使用带有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()并且我无法解决它。
答案 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)
}
这将按预期工作。