如何递归地使Enumerator循环文件内容尾部以避免堆栈溢出异常

时间:2014-09-01 16:22:11

标签: scala tail-recursion scalaz enumerator iterate

最近,我正在玩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))

有人可以告诉我如何重构这个吗?

非常感谢提前

0 个答案:

没有答案