考虑下面的代码:反向列表斯卡拉
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'? – Lutz
这个问题在很久以前就被问到了,但这里是你的尾递归问题的答案。是的,这是因为尾部递归优化。在你的第一个实现中,case(x :: xs)=> reverseList(xs)::: List(x),在递归调用reverseList之后,程序必须向它添加List(x)。这意味着它不能被优化成循环,在你的第二个例子中:case(x :: xs)=> {rlRec(x :: result,xs)} rlRec是最后一次调用,退出后没有任何操作,这就是为什么它不必为它创建一个新的Stack框架。 – loteq