## Flow control in Clojure (2021-11-16)

Languages > Clojure

## True or false

In Clojure the only “false” values are `false` and `nil`, all other values are logically true.

## If

``````(if condition then else) ;General form.
(if (even? 2) "even", "odd") ;For example this if will return "even".
(if (true? false) "Impossible") ;The else part is optional.``````

## If and do

``````(if (even? 2)
(do (println "even") true)
(do (println "odd") false)) ;do allows to create blocks of instructions.``````

## When

``````(when condition then) ;General form.
(when (even? 2) "even") ;When is like a if with only a then statement.
(when (even? 3) "even") ;If the condition is false when return nil.
(when (even? 2) (println "even") true) ;A do isn't needed to pack instructions.``````

## Cond

`cond` allows to pack conditions and to evaluate them in order. It will return the `then` part of the first true one, or `nil` in other cases.

``````(cond condition1 then1 conditionN thenN) ;General form.
(let [x 3]
(cond
(< x 2) "x < 2" ;This is false so the evaluation continue.
(< x 4) "x < 4" ;This is true so "x < 4" is returned;
)) ;With x = 1 the result will be "x < 2", and nil with x = 5.
(let [x 5]
(cond
(< x 2) "x < 2"
:else "x >= 2" ;Don't return nil in default case.
)) ;Every true value other than :else can work.``````

## Case

`case` compares, in constant time, a value to a series of literals to find a match. It will return the `then` part of the matched literal, or throw an exception if there’s no matches.

``````(case literal1 then1 literalN thenN) ;General form.
(let [x 5]
(case x
2 "x is 2" ;This is false so the evaluation continue.
5 "x is 5" ;This is true so "x is 5" is returned;
)) ;With x = 1 a "IllegalArgumentException No matching clause" would be thrown.
(let [x 1]
(case x
2 "x is 2"
5 "x is 5"
"x is not in the list" ;To avoid that a default result can be defined.
))``````

## Iteration

``````(dotimes [var n] expression) ;Evaluate the expression n times, then return nil.
(dotimes [i 3] (print i)) ;Will print '012'.
(doseq [var sequence] expression) ;Iterate over a sequence, then return nil.
(let [s [9 5 7]]
(doseq [n s]
(print n) ;Will print '957'.
))
(let [letters [:a :b] numbers [1 2]]
(doseq [l letters n numbers] ;With multiple sequences is similar to nested loops.
(pr l n) ;Will print '[:a 1][:a 2][:b 1][:b 2]'.
))``````

## For

In Clojure `for` is a list comprehension not a loop.

``````(for [var sequence] var) ;Will return a list containing all the sequence values.
(for [i [1 2 3]] i) ;Will return (1 2 3).
(for [i [1 2] j [3 4] ;Like for doseq.
(* i j)) ;Will return (3 4 6 8).``````

## Recursion

``````(loop [var1 value1 varN valueN] ;loop defines binding.
expression1
expressionN
(recur newValue1 newValueN)) ;recur re-executes the loop with new values.
(loop [i 0] ;i is initially 0.
(if (< i 10) ;If i is lesser than 10.
(recur (inc i)) ;Increment i by 1 and re-execute the loop.
i)) ;Else return i, so 10.
(defn increase [i n] ;Function arguments are implicit loop bindings.
(if (< i n)
(recur (inc i) n) ;recur must provide a value for all bindings.
i))``````

Clojure’s collections (Previous chapter) < Flow control in Clojure