1

最近,我在玩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获取信号DoneCont,如果是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))

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

提前谢谢了

4

0 回答 0