Clojure loop: doseq,dotimes, while, loop, recur

In Clojure loop can be performed using doseq, dotimes, while,loop, loop/recur and defn/recur functions.

doseq
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

(doseq [n (range 3)] ;;binding each value from the seq to n
(println n))

Result : (0 1 2)

dotimes
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]
(println i))

dotimes

while
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)))

while.JPG

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
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.

loop

defn/recur
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))
i))
(increase 1)

defnRecur

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

http://stackoverflow.com/questions/1662336/clojure-simple-factorial-causes-stack-overflow

(defn fact[x] (if (<= x 1) 1 (* x (fact (- x 1)) )))

(fact 1000) ;; throws arithmeticException integer overflow

ArithmeticOverflow.JPG

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

def_recur.JPG

(defn factorial ([x] (factorial 1 x))
([accum x]
(if (<= x 1) accum
(recur(*' accum x)(- x 1)))))
(factorial 1)

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s