考慮下面的代碼:反向列表斯卡拉
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