loop
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 (http://en.wikipedia.org/wiki/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"
[max]
(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
user> (geometric-series 1)
0.5
user> (geometric-series 2)
0.75
user> (geometric-series 10)
0.9990234375
user> (geometric-series 50)
0.9999999999999991
user> (geometric-series 100)
1.0
user> (geometric-series 1000)
1.0
user> ; converged to 1
ClojureDocs
Clojure.org, Special Forms, loop
http://clojure.org/special_forms#Special%20Forms–(loop%20[bindings%20]%20exprs
Introduction to Clojure, Looping and Recursion
http://clojure-doc.org/articles/tutorials/introduction.html#looping-and-recursion
Clojure from the ground up: macros, Recursion
http://aphyr.com/posts/305-clojure-from-the-ground-up-macros
Clojure for the Brave and True, Do Things, 4.3. loop
GetClojure