私が正しく理解していれば、scala.util.control.TailCallsを使用して、トランポリンを使用して非末尾再帰関数のスタックオーバーフローを回避できます。 APIに与えられた例は単純です:あなたは recursve呼び出しの後にいくつかの操作を行いたい場合TailCallsの使い方は?
import scala.util.control.TailCalls._
def isEven(xs: List[Int]): TailRec[Boolean] =
if (xs.isEmpty) done(true) else tailcall(isOdd(xs.tail))
def isOdd(xs: List[Int]): TailRec[Boolean] =
if (xs.isEmpty) done(false) else tailcall(isEven(xs.tail))
isEven((1 to 100000).toList).result
しかし、より興味深いケースです。私は何とか
def fac(n:Long): TailRec[Long] =
if (n == 0) done(1) else done(n * tailcall(fac(n - 1)).result)
によって実行されている「ナイーブ」階乗の実装を得たが、これは恐ろしい見て、私はこれが意図された使用であることを疑います。だから私の質問は、TailCallsを使用して階乗またはフィボナッチ関数を正しく書く方法です(はい、私はそれらをテール再帰的に得るためにアキュムレータを使う方法を知っています)?またはTailCallsはこの種の問題には適していませんか?
「scala.util.control.TailCallsはハックです」と言えば、使用するのが適切かどうかをもっと教えてください。 –
「ハック」はここでは敬意を表していませんでした。 TailCallsは、相互に再帰的な呼び出しからのスタックオーバーフローを避けるために使用するのに完全に適しています。 –