Learning Clojure and trying to understand the implementation:
What\'s the difference from:
(def factorial
(fn [n]
(loop [cnt n acc 1]
(if (z
Are Clojure's loop
and recur
forms specifically designed to code a simple imperative loop?
Yes.
In functional terms:
Clojure's recur
makes a tail-recursive call to the surrounding recursion point.
Instead of being stacked up, each successive recur
call overwrites the last.
A recursion point is
fn
form, possibly disguised in defn
or letfn
ORloop
form, which also binds/sets-up/initialises the
locals/variables. So your factorial
function could be re-written
(def factorial
(fn [n]
((fn fact [cnt acc]
(if (zero? cnt)
acc
(fact (dec cnt) (* acc cnt))))
n 1)))
... which is slower, and risks stack overflow.
Not every C/C++ loop translates smoothly. You can get trouble from nested loops where the inner loop modifies a variable in the outer one.
By the way, your factorial
function
1.0
instead of 1
to get floating point (double)
arithmetic, or use *'
instead of *
to get Clojure's BigInt
arithmetic.A quick fix for the latter is
(def factorial
(fn [n]
(loop [cnt n acc 1]
(if (pos? cnt)
(recur (dec cnt) (* acc cnt))
acc))))
; 1
... though it would be better to return nil
or Double.NEGATIVE_INFINITY
.