liveBook · Manning

Loop

As explained in Clojure: The Essential Reference

A loop is a language construct that repeatedly evaluates a body while passing through successive control states or values.

A loop repeats work while control values change. In Clojure, `loop` binds initial local values and `recur` supplies their values for the next pass. Unlike a Java `for` loop, this does not require a mutable counter or an outer collection to hold the result. section 3.4 section 3.4.1

(loop [i 0 s []]
  (if (< i 10)
    (recur (inc i) (conj s (* i i)))
    s))
;; [0 1 4 9 16 25 36 49 64 81]

The counter starts at zero and the result starts as an empty vector. Each `recur` passes an incremented counter and a vector with one more square; when the test fails, the loop returns the vector. section 3.4

Choose the iteration form to match the work:

  • Use `loop`/`recur` when successive local values determine the next step or when a computed result must be returned. `recur` targets the innermost enclosing `loop` or function, must be in tail position, and avoids consuming stack space on each pass. section 3.4.1
  • Use `while` when a changing test depends on a side effect, particularly at a Java I/O boundary. It tests before each pass, so its body may not run; the loop terminates with `nil`. section 3.4.4
  • For ordinary sequence work, prefer `range` with operations such as `map`, `filter`, or `for`. Use `dorun` when the purpose is to execute effects rather than retain the generated values. section 3.4.4
(defn fib [n]
  (loop [a 1 b 0 cnt n]               ; #1
    (if (zero? cnt)
      b
      (recur (+ a b) a (dec cnt)))))

(map fib (range 10))
;; (0 1 1 2 3 5 8 13 21 34)

This Fibonacci function keeps its changing values inside `loop`, leaving the function argument alone. The zero-count branch returns the answer; the other branch supplies all three bindings to `recur`. section 3.4.1

A side-effecting `while` is not a substitute for a value-producing `loop`: repeatedly reading a Java input stream until its end is a fitting use, while accumulating values in a mutable atom is discouraged. For performance-sensitive iteration, `loop` can also propagate type information that helps avoid unnecessary boxing. section 3.4 section 3.4.1 section 3.4.4

How Clojure: The Essential Reference covers it

How deep it goes
Explains loop bindings, recur targets and tail-position requirements, then distinguishes while’s test-and-body contract.
Examples
Works through squared numbers and Fibonacci, alongside stream hashing, a status thread, and sequence-based printing.
What it assumes
Introduces loop/recur syntax while using basic Clojure expressions and a Java for-loop for comparison.
What you can do after
Build it from scratch with loop/recur, or choose while for side-effecting tests and sequence operations for ordinary iteration.
How it connects
Connects iteration to recursion, tail recursion, mutable state, sequence operations, Java interoperability, and boxing.

Also explained in

Compare how 27 books explain loop →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Clojure: The Essential Reference. The section links point to the parts of the book it draws on.