【发布时间】:2011-11-12 19:48:04
【问题描述】:
给定以下代码:
import scala.util.Random
object Reverser {
// Fails for big list
def reverseList[A](list : List[A]) : List[A] = {
list match {
case Nil => list
case (x :: xs) => reverseList(xs) ::: List(x)
}
}
// Works
def reverseList2[A](list : List[A]) : List[A] = {
def rlRec[A](result : List[A], list : List[A]) : List[A] = {
list match {
case Nil => result
case (x :: xs) => { rlRec(x :: result, xs) }
}
}
rlRec(Nil, list)
}
def main(args : Array[String]) : Unit = {
val random = new Random
val testList = (for (_ <- 1 to 2000000) yield (random.nextInt)).toList
// val testListRev = reverseList(testList) <--- Fails
val testListRev = reverseList2(testList)
println(testList.head)
println(testListRev.last)
}
}
为什么函数的第一个版本失败(对于大输入),而第二个变体有效。我怀疑这与尾递归有关,但我不太确定。有人可以给我“傻瓜”的解释吗?
【问题讨论】:
-
为什么不使用'val testListRev = testList.reverse'?
-
这个问题是很久以前提出的,但这里是你的尾递归问题的答案。是的,这是因为尾递归优化。在您的第一个实现中,case (x :: xs) => reverseList(xs) ::: List(x),在递归调用 reverseList 之后,程序必须将 List(x) 添加到其中。这意味着它不能被优化成一个循环,在你的第二个例子中: case (x :: xs) => { rlRec(x :: result, xs) } rlRec 是最后一次调用,退出后无事可做,这就是为什么它不必为它创建一个新的堆栈框架。
标签: list scala recursion functional-programming tail-recursion