我已经阅读过帖子,提到Scala有尾递归优化。
但是这个怎么样:
def f(i: Int): List[Int] = {
if (i == 0)
Nil
else
i :: f(i - 1) // Is there any optimizations?
}
第5行不是尾递归。
Scala对它有一些优化吗?或者它可能会消耗更多的堆栈空间然后它的命令式版本?
答案 0 :(得分:3)
目前,此代码将计算单独堆栈帧中的每个递归。如果i
足够大,那么就会耗尽内存。
scala> f(10000)
java.lang.StackOverflowError
at .f(<console>:15)
at .f(<console>:15)
at .f(<console>:15)
因此编译器无法帮助提高效率。
你可以防止i
太大(如果它适用于你的要求,但也许不是很好),或者让它尾递归,这样它就可以在恒定的堆栈空间中计算。
作为一个例子。
scala> @tailrec def f(i: Int, x: List[Int] = List()): List[Int] = {
| if (i == 0)
| x.reverse
| else
| f(i - 1, i :: x)
| }
f: (i: Int, x: List[Int])List[Int]
scala> f(10)
res10: List[Int] = List(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
请注意,在返回列表(x.reverse
)之前,它的反转是0(n)
(复杂性),但只有在你需要它时才显然需要它。
答案 1 :(得分:2)
使用scalaz trampoline
object tail {
def f(i: Int): Trampoline[List[Int]] = {
if (i == 0)
Trampoline.done(Nil)
else
Trampoline.suspend(f(i - 1)).flatMap { list =>
Trampoline.done((i :: list))
}
}
def main(args: Array[String]): Unit = {
println(f(1000).run)
}
}
并且不存在堆栈问题