2013-05-20 15 views
10

To jest kod seplicowy, który używa rekursji ogonowej.Rekursja ogona w clojure

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

Przełożę to na kod clojure, oczekując optymalizacji rekursji tego samego ogona.

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

Jednakże mam to całkowitą przelewowy (nie przepełnienie stosu), nawet w małej ilości, takie jak (fact 1 30).

Próbowałem z recur, ale dostałem ten sam błąd.

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

Co jest nie tak z kodem clojure?

+7

Ponadto warto zauważyć, że Clojure, z powodu ograniczeń JVM, nie umożliwia automatyczną optymalizację połączeń ogon. 'recur' jest w istocie sposobem na zastosowanie idiomu rekursywnego w tym przypadku. – JohnJ

+0

Gdzie w dokumentach clojure mogę znaleźć przykłady użycia recur bez pętli? Sposób, w jaki użyłeś go tutaj. – SultanLegend

Odpowiedz

18

Nic, po prostu użyć BigInt s:

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

Argumenty mogą być małe, ale wynik nie jest!

Zauważ, że zaznaczone wersje arytmetycznych operatorów są również dostępne, które wspierają arbitralne PRECISION

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