Skip to content

Branching

These forms test a value and choose one of several results. Loop covers repeating a body.

if

if takes a test, a value when it is truthy, and an optional value otherwise:

user=> (if (> 3 4) "big" "small")
"small"
user=> (if (> 3 4) "big")
nil

Remember that only nil and false are falsey; 0 is true.

when

when runs several forms only if the test is truthy:

user=> (when true (println "one") (println "two"))
one
two
nil

when-not

when-not is the opposite of when: it runs the forms only if the test is falsey:

user=> (when-not false :ok)
:ok

if-not

if-not is if with the branches swapped:

user=> (if-not (empty? [1]) "has items" "empty")
"has items"

cond

cond takes pairs of test and result and returns the first result whose test is truthy. :else is just a keyword, which is truthy, so it works as the last test:

(defn power-band [power]
  (cond
    (> power 0.8) "fast"
    (> power 0.2) "cruising"
    :else "slow"))
user=> (power-band 0.9)
"fast"
user=> (power-band 0.5)
"cruising"
user=> (power-band 0.1)
"slow"

Without a final :else, a cond with no match returns nil.

case

case compares one value with constants, which suits a state machine. The constants are not evaluated, and a list of constants matches any of them:

(defn describe [state]
  (case state
    :intake "running the intake"
    (:score :dump) "scoring"
    "idle"))
user=> (describe :intake)
"running the intake"
user=> (describe :dump)
"scoring"
user=> (describe :teleop)
"idle"

The last form is the default when it is not paired with a constant. Without a default, an unmatched value is an error rather than nil, which catches typos:

user=> (case :x :a 1)
Execution error: No matching clause: :x

let

let names values for the rest of the body. Bindings are sequential, so a later one can use an earlier one:

user=> (let [a 1 b (+ a 1)] [a b])
[1.0 2.0]

Bindings are local to the body and shadow outer names. let can also destructure; see Functions.

if-let

if-let binds a value and runs only when it is truthy, which saves a lookup and a test:

user=> (if-let [speed (:speed {:name "Bolt"})] speed 0)
0.0
user=> (if-let [speed (:speed {:speed 0.5})] speed 0)
0.5

nil counts as no value, so this is the natural companion to get, whose default is nil when you omit it.

when-let

when-let does the same as if-let, without an else branch:

user=> (when-let [x 5] (* x 2))
10.0

and, or and do

and returns the last truthy value or the first falsey one; or returns the first truthy value. Both stop evaluating as soon as the answer is known:

user=> (and true 1 nil)
nil
user=> (or nil false 7)
7.0
user=> (and false (/ 1 0))   ; the division never runs
false

do runs several forms and returns the last, which is how you put more than one form where a single expression is expected:

user=> (do (println "a") 1)
a
1.0