我做了递归函数,就像
一样require : L (List[Int])
L模式匹配
Nil => Thread.dumpStack()
x :: xs => print(x) + function(xs)
def function(L : List[Int]) { L match { case Nil => Thread.dumpStack() case x :: xs => print(x + " "); function(xs) } }
val l =(1到5).toList // 功能(l)
所以我认为这个函数在堆栈框架中有n次,但它发生了一次,我认为这个函数已经找到Nil
并打印出异常Thread.dumpStack
。
scala编译器是智能还是其他?
答案 0 :(得分:7)
您正在观察尾递归:从一次迭代到下一次迭代没有任何内容存储,因此递归基本上由编译器转换为while循环。 (所以,是的,编译器很聪明。)
答案 1 :(得分:1)
正如Rex Kerr所指出的,这是应用尾调用优化的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
对其进行注释,如果无法对其进行优化,编译器将产生错误。