最近,我正在玩Rúnar撰写的Scalaz Tutorial: Enumeration-based I/O With Iteratees
我对枚举文件的实现有疑问。
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 获取信号完成或连续,如果它是 Cont ,它递归调用循环。
但是,这个循环不是尾递归,我使用带有编译错误的注释 @tailrec 。 所以,我认为问题是如果enumReader尝试读取一个大文件,它会有 stackoverflow异常。
另外,我认为很难的原因是因为通常当我们想要将正常递归改为尾递归时,我们会在参数中使用一些累加器,但在这种情况下,它是函数IterV [String,A] =&gt; IO [IterV [String,A]]
编辑: 此外,我认为当像计数这样的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))
有人可以告诉我如何重构这个吗?
非常感谢提前