Scalaは末尾再帰の最適化をサポートしていますか?
他のポスターが言っているように、Scalaはコンパイル時にテール再帰の最適化を行います。つまり、テール再帰関数の実行時にスタックトレースからわかるように、テール再帰関数はコンパイラーによってループに変換されます(メソッド呼び出しはジャンプに変換されます)。
次のスニペットを試してください:
def boom(n: Int): Nothing = if(n<=0) throw new Exception else boom(n-1)
boom(10)
スタックトレースを検査します。関数boomへの呼び出しが1つだけ表示されるため、コンパイルされたバイトコードは再帰的ではありません。
JVMレベルでのテールコールの実装 -についての提案があります。これは、私の意見では、JVMがコンパイル時の最適化ではなく、ランタイムの最適化を実行できるためコード-そして、おそらくより柔軟な末尾再帰を意味する可能性があります。基本的にtailcall invoke
は通常のメソッドinvoke
とまったく同じように動作しますが、安全な場合は呼び出し元のスタックをドロップします-JVMの仕様では、スタックフレームを保持する必要があると記載されているため、JITはいくつかの処理を行う必要がありますスタックフレームが使用されないかどうかを調べる静的コード分析。
現在の状態は proto 80% です。 Java 7(invokedynamic
の方が優先度が高く、実装はほぼ完了しています)に間に合うように完了するとは思いませんが、Java 8はそれが実装されているのを見るかもしれません。
Scala 2.8では、@tailrec
は、コンパイラが最適化すると期待する特定のメソッドをマークします。
import scala.annotation.tailrec
@tailrec def factorialAcc(acc: Int, n: Int): Int = {
if (n <= 1) acc
else factorialAcc(n * acc, n - 1)
}
メソッドを最適化できない場合は、コンパイル時エラーが発生します。
Scala 2.7.xは、最終メソッドとローカル関数の自己再帰(それ自体を呼び出す関数)の末尾呼び出しの最適化をサポートしています。
Scala 2.8には、トランポリンのライブラリサポートも付属している可能性があります。これは、相互再帰関数を最適化する手法です。
Scala再帰の状態に関するかなりの情報が Rich Doughertyのブログ にあります。