Part I. The language · this page as markdown
Tests and choices
A toy that says the same thing every time is a start. One that answers differently at night, or to a friend, or on the tenth ring, needs to choose. This chapter is about tests, which answer true or false, and the forms that choose with them.
Tests #
A test is a form that answers true or false:
(= 3 3)
(= "rose" "Rose")
(not= 3 4)
(< 2 5)
(>= 5 5)
(< 1 2 3)
(even? 4)
(zero? 0)
(pos? -1)
(nil? nil)
(empty? "")true
false
true
true
true
true
true
true
false
true
true= compares any two values, lists and maps too, and text by every character, so "rose" and "Rose" differ. (< 1 2 3) asks whether each number is less than the next. Words ending in ? are tests by custom.
and, or and not put tests together:
(and (> 5 3) (< 5 10))
(or (= 1 2) (= 2 2))
(not (= 1 2))true
true
trueWhat counts as true #
A choice doesn't need true exactly. Every value counts as true except two: false and nil. So 0, "" and [] count as true, and a word that answers nil when it finds nothing can be used as a test. and and or use this too: or answers the first value that counts as true, and and the last, or the first that doesn't.
(or nil "a fallback")
(or (get {:rings 4} :chimes) 0)
(and "rose" "sage")
(and nil "sage")"a fallback"
0
"sage"
nil(or (get m :k) 0) is a common way to say "the value, or 0 if there isn't one".
if #
if takes a test, a value for when it holds, and a value for when it doesn't:
(if (> 12 10) "a dozen or more" "fewer")
(let [rings 1]
(str "Rung " rings (if (= rings 1) " time" " times")))"a dozen or more"
"Rung 1 time"Inside a value, the third part can be left out, and the if answers nil when the test fails. At the top of a plan, an if that does something needs all three parts; when there is nothing to do otherwise, use when.
when #
when takes a test and any number of forms, and runs them only when the test holds:
(when (> 5 3) "yes")
(when (> 3 5) "no")
(str "a" (when false "b"))"yes"
"a"
Nothing at home changed.The second when did nothing at all, so it answered nothing. Inside a value, where something must be answered, a when whose test fails answers nil, which str writes as nothing: so the third answers "a".
when-not is when the other way round. if-let and when-let name a value and choose by it at once: the name is given only when the value counts as true.
(when-not (= 1 2) "they differ")
(if-let [guest (first ["@mira"])] (str "Hello, " guest) "Nobody yet")
(if-let [guest (first [])] (str "Hello, " guest) "Nobody yet")"they differ"
"Hello, @mira"
"Nobody yet"cond #
When there are more than two ways to go, cond takes tests and values in pairs and answers the value of the first test that holds. :else at the end is a test that always holds:
(let [rings 12]
(cond (= rings 0) "silent"
(< rings 10) "warming up"
(< rings 100) "well rung"
:else "a famous bell"))"well rung"The tests are tried in order, so put the narrowest first.
case #
case compares one value with constants written out (numbers, text, keywords), and answers the value beside the one that's equal. A list of constants matches any of them, and a last value on its own is what to answer otherwise:
(case :hazy
:sunny "Bright out."
(:hazy :rain) "A soft grey day."
"Some weather.")
(case 7 1 "one" 2 "two" "many")"A soft grey day."
"many"condp is case with a test of your choice: (condp = x 1 "one" 2 "two" "many").
Threading #
Choices often come at the end of a chain of small changes. -> passes a value through forms, each time as the first thing the next word takes, and ->> as the last. cond-> applies a step only when its test holds:
(-> {:rings 0} (assoc :rings 3) (update :rings inc))
(->> [3 1 2] (sort) (map inc))
(cond-> {:rings 3} true (update :rings inc) false (assoc :broken true)){:rings 4}
(2 3 4)
{:rings 4}(-> {:rings 0} (assoc :rings 3) (update :rings inc)) is (update (assoc {:rings 0} :rings 3) :rings inc), written in the order it happens.
Try it #
- Write a
condthat answers"cold","mild"or"warm"for a temperature below 10, below 20, or otherwise. - Use
caseto answer a greeting for:dawn,:day,:duskand:night. - What does
(or nil false)answer? And(and 1 2 3)? - With
if-let, answer the first even number in[1 3 4 5]doubled, or"none".
Recap #
- Tests answer
trueorfalse:=,not=,<,>,even?,nil?,empty?and the like;and,orandnotjoin them. - Only
falseandnilcount as false. ifchooses between two;whendoes something or nothing;condtries pairs in order;casecompares with constants.- At the top of a plan, an
ifneeds both its branches; usewhenfor one.
Next: working over a whole list at once.
Written by Claude, Plazmi's writer, for Plazmi, a service of Manatee Media LLC. Text © 2026 Manatee Media LLC. The examples are free to copy, change and run.