Loops and Recursion
Prerequisites: map, filter, and reduce
Clojure has no for (i = 0; ...) loop that changes a counter. You
iterate with sequence functions, with doseq for side effects, or with
recursion.
doseq and dotimes — for side effects
(doseq [fruit ["apple" "banana" "cherry"]]
(println "-" fruit))
(dotimes [i 3]
(println "Hip!" i))
(doseq [x [1 2]
y [:a :b]]
(println x y))
- apple
- banana
- cherry
Hip! 0
Hip! 1
Hip! 2
1 :a
1 :b
2 :a
2 :b
doseq runs its body for each item (nested bindings loop over every
combination) and returns nil. Use it for printing, writing files, or
other side effects.
for — building a sequence
(println (for [x (range 1 6)] (* x x)))
(println (for [x (range 1 4)
y (range 1 4)
:when (< x y)]
[x y]))
(println (for [n (range 10)
:let [sq (* n n)]
:while (< sq 30)]
sq))
(1 4 9 16 25)
([1 2] [1 3] [2 3])
(0 1 4 9 16 25)
for is a list comprehension: it returns a sequence. :when
filters, :let names intermediate values, and :while stops early.
loop and recur
(defn years-to-double [balance rate]
(loop [amount balance
years 0]
(if (>= amount (* 2 balance))
years
(recur (* amount (+ 1 rate)) (inc years)))))
(println (years-to-double 1000 0.07))
(defn factorial [n]
(loop [i n acc 1N]
(if (<= i 1) acc (recur (dec i) (* acc i)))))
(println (factorial 25))
11
15511210043330985984000000N
loopsets up bindings likelet;recurjumps back to theloopwith new values.recurmust be in tail position (the last thing evaluated), and it doesn't grow the stack — so it can loop millions of times.recuralso works directly in a function, jumping back to its start.
Plain recursion
(defn sum-tree [node]
(if (number? node)
node
(reduce + (map sum-tree node))))
(println (sum-tree [1 [2 3] [[4] 5]]))
15
Ordinary recursion is fine for trees and other shallow structures. For
long iterations, use recur or a sequence function — the JVM stack is
limited.
Practice
Print the multiplication table for 7, from 7 x 1 = 7 to
7 x 5 = 35.
Show solution
(doseq [i (range 1 6)]
(println "7 x" i "=" (* 7 i)))
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35