2011-12-22 12 views
5

Tôi gặp StackOverflowError cho đoạn mã sau:java.lang.StackOverflowError trong clojure đuôi đệ quy

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

mặc dù sử dụng vòng lặp sẽ làm cho nó hoạt động:

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

gì đi sai với mã trước không có vòng lặp?

Trả lời

7

lỗi của bạn là ở đây:

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

Bạn đang gọi điện thoại recursive-reverse với một đối số (vector). Điều này gọi cùng một danh sách đối số của hàm, do đó, nó đệ quy và tạo khung ngăn xếp mỗi lần.

Thay đổi nó để:

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

và bạn sẽ có ngay.

(Ngoài ra, vấn đề riêng biệt, nhưng tôi sẽ thường làm kiểm tra cho nil hơn '() và sử dụng next hơn rest. Tôi không nghĩ rằng nó có bất kỳ lợi thế thực sự về hiệu suất hoặc bất cứ điều gì, nhưng có vẻ sạch hơn để tôi.)

+1

Cảm ơn. Tinh thể rõ ràng bây giờ. – lkahtz

+3

'(nil? X)' có thể nhanh hơn '(= x())', bởi vì trình biên dịch có thể phát ra chỉ một hoạt động bytecode đơn, kiểm tra null nguyên thủy mà Java sử dụng. Tất nhiên, sau này là khá nhanh, nhưng tôi nghi ngờ nó là nhiều lần chậm hơn so với trước đây. Khi điều đó xảy ra, kiểm tra nil được tối ưu hóa này chưa được thực hiện (nhưng?), Nhưng đó là một tối ưu hóa hợp lý có thể được thực hiện sau cùng. – amalloy

1

này đã làm việc cho tôi:

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

Bạn đã vượt qua đối số cho recursive-reverse bên trong một vài dấu ngoặc không cần thiết, đó là tất cả.