The loop special form is not like a for loop. The usage of loop is the same as the let binding. However, loop sets a recursion point. The recursion point is designed to use with recur, which means loop is always used with recur. To make a loop happen, the number of arguments (arity) specified for recur’s must coincide with the number of bindings for loop. That way, recur goes back to loop.

The syntax is: (loop [bindings*] exprs*)

user> (loop [coll ["hello" "world" "love" "coding"] result "Words: "]   ; 2 bindings
        (if (= 1 (count coll)) (str result (first coll))
            (recur (rest coll) (str result (first coll) ", "))))  ; arity 2
"Words: hello, world, love, coding"

Compare the example above with the one in recur.

For a loop exercise, let’s think about how to calculate the sum of a geometric series ( A well-known geometric series is 1/2 + 1/4 + 1/8 + 1/16 + …., which converges to 1.

user> (defn geometric-series
        "takes maximum number of elements,
         calculates geometric series"
        (loop [n 1 acc 0]                                      ; 2 bindings
          (if (> n max) acc
            (recur (inc n) (+ acc (/ 1 (Math/pow 2N n)))))))   ; arity 2
user> (geometric-series 1)
user> (geometric-series 2)
user> (geometric-series 10)
user> (geometric-series 50)
user> (geometric-series 100)
user> (geometric-series 1000)
user> ; converged to 1