最近,我在玩Scalaz Tutorial: Enumeration-based I/O With Iteratees,作者是 Rúnar
我对枚举文件的实现有疑问。
def enumReader[A](r: BufferedReader,
it: IterV[String, A]): IO[IterV[String, A]] = {
@tailrec
def loop: IterV[String, A] => IO[IterV[String, A]] = {
case i@Done(_, _) => IO { i }
case i@Cont(k) => for {
s <- IO { r.readLine }
a <- if (s == null) IO { i } else loop(k(El(s)))
} yield a
}
loop(it)
}
我对代码的理解: enumReader 正在从iteratee获取信号Done或Cont,如果是Cont,它会递归调用循环。
但是,这个循环不是尾递归的,我使用注释@tailrec时出现编译错误。所以,我认为问题是如果 enumReader 尝试读取一个大文件,它将有stackoverflow 异常。
另外,我认为很难的原因是因为通常当我们想将普通递归更改为尾递归时,我们会在参数中使用一些累加器,但在这种情况下,它是一个函数 IterV[String, A] = > IO[IterV[字符串,A]]
编辑:此外,我认为像Count这样的Iteratee 方法也可能具有相同的stackoverflow异常。
def counter[A]: IterV[A,Int] = {
def step(n: Int): Input[A] => IterV[A,Int] = {
case El(x) => Cont(step(n + 1))
case Empty => Cont(step(n))
case EOF => Done(n, EOF)
}
Cont(step(0))
有人可以告诉我如何重构这个吗?
提前谢谢了