In Clojure loop can be performed using doseq, dotimes, while,loop, loop/recur and defn/recur functions.
doseq function iterates over a sequence performing something against each element. It is similar to foreach in C#.
doseq forces evaluation for a lazy sequence
(doseq [n (range 3)] ;;binding each value from the seq to n
Result : (0 1 2)
dotimes function evaluates same expression n times similar to for loop in C#.
dotimes takes a name and a value vector and performs the expression inside of it number of times based on value passed.
(dotimes [i 3]
while function in clojure is similar to while in C#.
while continues evaluating the body as long as the condition is true
(def a (atom 10))
(while (< 0 @a) (do (println @a) (swap! a dec)))
In the above example, an atom with initial value of 10 is created and assigned to symbol a.
Atoms provide a way to manage shared, synchronous, independent state. They are a reference type like refs, i.e, points to a value.
The swap function updates the value of the atom.
The dec function substracts 1 from the atom value.
The while is executed until the atom a value is no longer less than 0.
loop/recur takes a binding vector and a condition is defined and recur is used to re-execute loop with new bindings.
(loop [i 0]
(if(< i 10)
(recur (inc i)) i))
In the example above loop initialises i down to 0 and iteratively increments by 1 with the help of recur until i is 10.
defn/recur can act as loop expressions in the sense that a recur inside the function is meaningful and results in the functions being called again with new bindings as specified by recur.
(defn increase [i]
(if(< i 10)
(recur (inc i))
In above example, the loop from previous example is defined into a named function increase that takes a single argument. if a number less than 10 is passed, increase will loop some number of times and return i until 10 is reached.
An example how the defn/recur is useful is the factorial function found from
(defn fact[x] (if (<= x 1) 1 (* x (fact (- x 1)) )))
(fact 1000) ;; throws arithmeticException integer overflow
The factorial function breaks with integer overflow with 1000.
The combination of defn/recur can be used to prevent the error
Clojure uses the tail-call optimisation so that the overflow does not occur
(defn factorial ([x] (factorial 1 x))
(if (<= x 1) accum
(recur(*' accum x)(- x 1)))))