To build on @A.Webb's answer and @amalloy's comment:
recur
is not a shorthand to call the function and it's not a function. It's a special form (what in another language you would call a syntax) to perform tail call optimization.
Tail call optimization is a technique that allows to use recursion without blowing up the stack (without it, every recursive call adds its call frame to the stack). It is not implemented natively in Java (yet), which is why recur
is used to mark a tail call in Clojure.
Recursion using lazy-seq
is different because it delays the recursive call by wrapping it in a closure. What it means is that a call to a function implemented in terms of lazy-seq
(and in particular every recursive call in such a function) returns (immediately) a LazySeq
sequence, whose computation is delayed until it is iterated through.
To illustrate and qualify @amalloy's comment that recur
and laziness are mutually exclusive, here's an implementation of filter
that uses both techniques:
(defn filter [pred coll]
(letfn [(step [pred coll]
(when-let [[x & more] (seq coll)]
(if (pred x)
(cons x (lazy-seq (step pred more))) ;; lazy recursive call
(recur pred more))))] ;; tail call
(lazy-seq (step pred coll))))
(filter even? (range 10))
;; => (0 2 4 6 8)
Both techniques can be used in the same function, but not for the same recursive call ; the function wouldn't compile if the lazy recursive call to step
used recur
because in this case recur
wouldn't be in tail call position (the result of the tail call would not be returned directly but would be passed to lazy-seq
).