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

Something to say?

Leave a Reply

Your email address will not be published.