2013-05-20 66 views
10

這是一個使用尾遞歸的lisp代碼。clojure中的尾遞歸

(defun factorial (f n) 
    (if (= n 1) 
     f 
     (factorial (* f n) (- n 1)))) 

我把它翻譯成期待相同的尾遞歸優化的clojure代碼。

(defn fact [f n] 
    (if (= n 1) 
     f 
     (fact (* f n) (dec n)))) 

但是我得到這個整數溢出(未堆棧溢出),即使有少數如(fact 1 30)

ArithmeticException integer overflow clojure.lang.Numbers.throwIntOverflow (Numbers.java:1374) 

我試着用recur,但得到了同樣的錯誤。

(defn factorial [f n] 
    (if (= n 1) 
     f 
     (recur (* f n) (dec n)))) 

clojure代碼有什麼問題?

+7

另外值得注意的是Clojure的,因爲JVM的限制,不支持自動尾調用優化。在這種情況下,「recur」確實是一種遞歸習慣用法。 – JohnJ

+0

在clojure文檔中,我可以找到使用沒有循環的循環的例子嗎?你在這裏使用它的方式。 – SultanLegend

回答

18

沒什麼,只是用BigInt S:

(factorial 1N 30N) ;=> 265252859812191058636308480000000N 

的參數可能很小,但結果是不是!

注意打勾算術運算符的版本也可以,它支持任意精度:

(reduce *' (range 1 31)) ;=> 265252859812191058636308480000000N