1

最近、私はScalaz チュートリアルで遊んでいました: Rúnar によって書かれた反復ベースの I/O

ファイルの列挙の実装について質問があります。

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の場合、 loop を再帰的に呼び出します。

ただし、このループは末尾再帰ではありません。注釈@tailrecを使用してコンパイル エラーを発生させます。したがって、 enumReader が大きなファイルを読み込もうとすると、stackoverflow exceptionが発生することが問題だと思います。

また、難しいと思う理由は、通常、通常の再帰を末尾再帰に変更したい場合、パラメーターでアキュムレータを使用するためですが、この場合、それは関数 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