Skip to content
AgileLogics
6 min read

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
  • loop sets up bindings like let; recur jumps back to the loop with new values.
  • recur must be in tail position (the last thing evaluated), and it doesn't grow the stack — so it can loop millions of times.
  • recur also 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