【发布时间】:2009-11-04 23:35:47
【问题描述】:
Scala 是否支持尾递归优化?
【问题讨论】:
标签: performance scala tail-recursion
Scala 是否支持尾递归优化?
【问题讨论】:
标签: performance scala tail-recursion
正如其他发帖人所说,Scala 在编译时进行尾递归优化。也就是说,一个尾递归函数被编译器转化为一个循环(方法调用被转化为一个跳转),从运行尾递归函数时的堆栈跟踪可以看出。
试试下面的 sn-p:
def boom(n: Int): Nothing = if(n<=0) throw new Exception else boom(n-1)
boom(10)
并检查堆栈跟踪。它只会显示对函数 boom 的一次调用——因此编译后的字节码不是递归的。
有一个关于implement tail calls at the JVM level 的提议——在我看来这是一件很棒的事情,因为这样 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 支持对 final 方法和局部函数的自递归(一个函数调用自身)进行尾调用优化。
Scala 2.8 也可能带有对 trampoline 的库支持,这是一种优化相互递归函数的技术。
关于 Scala 递归状态的大量信息可以在 Rich Dougherty's blog 中找到。
【讨论】:
【讨论】: