web-dev-qa-db-ja.com

Scalaは末尾再帰の最適化をサポートしていますか?

Scalaは末尾再帰の最適化をサポートしていますか?

62
Roman Kagan

他のポスターが言っているように、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はそれが実装されているのを見るかもしれません。

68
Flaviu Cipcigan

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)
}

メソッドを最適化できない場合は、コンパイル時エラーが発生します。

42

Scala 2.7.xは、最終メソッドとローカル関数の自己再帰(それ自体を呼び出す関数)の末尾呼び出しの最適化をサポートしています。

Scala 2.8には、トランポリンのライブラリサポートも付属している可能性があります。これは、相互再帰関数を最適化する手法です。

Scala再帰の状態に関するかなりの情報が Rich Doughertyのブログ にあります。

12

関数が自己再帰的である非常に単純な場合のみ。

テール再帰能力の証明

Scala= 2.8は、末尾再帰の認識を改善している可能性があります。

7
Stefan Kendall