最近、私は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))
誰かがこれをリファクタリングする方法を教えてもらえますか?
よろしくお願いします