Rex Kerrは、tail呼び出し最適化を適用したScalaコンパイラを指摘しています。あなたが最後にコンパイルされているかを知りたい場合は、追加の引数を指定してコンパイラを実行することができます
scalac -Xprint:tailcalls yourfile.scala
これはtailcalls
コンパイラのフェーズ後の中間表現を出力します。 (あなたはについてのすべてのフェーズを学びたいのであれば、あなたもscalac -Xshow-phases
を実行することができます。)例えば、以下の入力に:
object TailRec {
def foo(l : List[Int]) : Unit = l match {
case Nil => Thread.dumpStack()
case x :: xs => println(x); foo(xs)
}
}
コンパイラは(機能foo
用)を印刷します:
def foo(l: List[Int]): Unit = {
<synthetic> val _$this: TailRec.type = TailRec.this;
_foo(_$this,l){
l match {
case immutable.this.Nil => java.this.lang.Thread.dumpStack()
case (hd: Int, tl: List[Int])collection.immutable.::[Int]((x @ _), (xs @ _)) => {
scala.this.Predef.println(x);
_foo(TailRec.this, xs)
}
}
}
}
部分_foo(_$this,l)
は関数定義のように見えますが、実際にはラベルであり、 "call" _foo(TailRec.this, xs)
は実際にそのラベルにジャンプしています。要するに、コンパイラは再帰呼び出しを実際にwhileループに書き換えました。
可能であればコンパイラは最適化を自動的に適用します。関数が適切に書き換えられるようにするには、@tailrec
と注釈を付けることができます。最適化できない場合、コンパイラはエラーを生成します。
-1明確にしてください:質問を説明するために、短いコードサンプルとREPLのトランスクリプトを提供してください。 – retronym