2012-04-11 39 views
2

根據MSDN文檔,在編寫遞歸函數時,使用累加器參數會使函數尾遞歸,從而節省堆棧空間。 我使用MSDN網站給出了兩個例子在列表 -爲什麼tail遞歸函數對於正常遞歸函數成功執行的輸入失敗?

第一無尾計算所有數字的總和recursion-

let rec Sum myList = 
    match myList with 
    | [] -> 0 
    | h::t -> h + Sum t 

現在用尾巴recursion-

let Sumtail list = 
    let rec loop list acc = 
     match list with 
     | h::t -> loop t acc + h 
     | [] -> acc 
    loop list 0 

並使用輸入[1..100000]運行這兩個函數。 函數Sum成功地計算了此列表的總數,但給出了stackoverflow例外,如果我通過[1..1000000] ,但第二個函數Sumtail未能在[1..100000],同時它應該提供更好的性能,因爲它使用尾遞歸的第一個函數。 是否還有其他影響遞歸函數的因素?

+3

我相信你誤解了某些東西 - 使用累加器參數不會產生函數尾遞歸。累加器參數是一種用於在使用尾遞歸函數時累加值的技術。這是一種通常會產生尾遞歸的技術,但它沒有定義尾遞歸。 – 2012-04-11 13:30:01

回答

10

你的第二個功能是不是尾遞歸,因爲loop t acc + h被解析爲(loop t acc) + h這使得+成爲loop最後一次操作。

loop t acc + h更改爲loop t (acc + h)以使函數變成尾遞歸。

+0

那是正確的,但我不能標記它正確答案(仍然是6分鐘)。這是什麼差異? – Kapil 2012-04-11 12:28:54

+2

必須將'+'運算符應用於循環中的返回值,因此編譯器不能使用尾遞歸,這會忘記每次遞歸調用的h狀態。如果可以忘記狀態 - 如果我們知道返回值將通過所有未修改的堆棧幀返回,則尾遞歸將起作用。 – 2012-04-11 12:37:00