2011-12-22 110 views
5

我遇到的StackOverflowError以下代碼:java.lang.StackOverflowError的Clojure中尾遞歸

(defn recursive-reverse 
    ([coll] (recursive-reverse [coll nil])) 
    ([coll acc] 
    (if (= coll '()) acc 
     (recur (rest coll) (cons (first coll) acc))))) 

雖然使用循環會使其工作:

(defn recursive-reverse [lst] 
    (loop [coll lst acc nil] 
    (if (= coll '()) acc 
     (recur (rest coll) (cons (first coll) acc))))) 

錯在現有代碼沒有循環?

回答

7

你的錯誤是在這裏:

([coll] (recursive-reverse [coll nil])) 

你打電話recursive-reverse有一個參數(矢量)。這將調用該函數的相同參數列表,因此它會遞歸執行並每次創建一個堆棧幀。

將其更改爲:

([coll] (recursive-reverse coll nil)) 

,你應該是正確的。

(同樣,單獨的問題,但我一般不檢查nil,而不是'()和使用next而非rest,我不認爲它在性能或任何方面的任何真正的優勢,但它似乎吸塵器我)。

+1

謝謝。現在清澈透明。 – lkahtz 2011-12-22 01:08:40

+3

'(nil?x)'可能比'(= x())'快得多,因爲編譯器只能發出一個字節碼操作,即Java使用的原始空值檢查。當然,後者非常快,但我懷疑它比前者慢好幾倍。碰巧,這個優化的無檢查沒有實現(但?),但這是一個合理的優化,最終可能會做出。 – amalloy 2011-12-22 02:05:57

1

這爲我工作:

(defn recursive-reverse 
    ([coll] (recursive-reverse coll nil)) 
    ([coll acc] 
    (if (= coll '()) acc 
     (recur (rest coll) (cons (first coll) acc))))) 

您傳遞的參數recursive-reverse幾個不必要的括號內,僅此而已。