我似乎誤解了尾遞歸;根據to this stackoverflow question R不支持尾遞歸。然而,讓我們來看看下面的函數來計算第n個斐波納契數:R中的尾遞歸
迭代版本:
Fibo <- function(n){
a <- 0
b <- 1
for (i in 1:n){
temp <- b
b <- a
a <- a + temp
}
return(a)
}
「天真」遞歸版本:
FiboRecur <- function(n){
if (n == 0 || n == 1){
return(n)
} else {
return(FiboRecur(n-1) + FiboRecur(n-2))
}
}
最後一個例子,我發現,應該是尾調用遞歸:
FiboRecurTail <- function(n){
fib_help <- function(a, b, n){
if(n > 0){
return(fib_help(b, a+b, n-1))
} else {
return(a)
}
}
return(fib_help(0, 1, n))
}
現在,如果我們看看跟蹤■當這些函數被調用,這裏是我們得到:
Fibo(25)
trace: Fibo(25)
[1] 75025
trace(FiboRecur)
FiboRecur(25)
Thousands of calls to FiboRecur and takes a lot of time to run
FiboRecurTail(25)
trace: FiboRecurTail(25)
[1] 75025
在Fibo(25)
和FiboRecurTail(25)
的情況下,瞬間顯示的答案,只有一個調用。對於FiboRecur(25)
,進行了數千次呼叫,並在顯示結果之前運行幾秒鐘。
我們也可以使用benchmark
功能從包裝rbenchmark
看看運行時間:
benchmark(Fibo(30), FiboRecur(30), FiboRecurTail(30), replications = 5)
test replications elapsed relative user.self sys.self user.child sys.child
1 Fibo(30) 5 0.00 NA 0.000 0 0 0
2 FiboRecur(30) 5 13.79 NA 13.792 0 0 0
3 FiboRecurTail(30) 5 0.00 NA 0.000 0 0 0
所以,如果R不支持尾遞歸,什麼FiboRecurTail(25)
,使得它運行速度正在發生作爲迭代版本,而「天真」遞歸函數像糖漿一樣運行?相反,R支持尾遞歸,但沒有像其他編程語言(例如Haskell)那樣優化一個函數的「天真」遞歸版本作爲尾調用遞歸呢?這是我從這個post in R's mailing list瞭解到的。
我非常感謝,如果有人會對此有所瞭解。謝謝!
你說得對,我已經糾正了這一點。 – brodrigues
[R統計環境下的尾遞歸]可能的重複(http://stackoverflow.com/questions/13208963/tail-recursion-on-r-statistical-environment) –