Common Lisp provides the programmer with several different conditionals that can be categorised by the number of "branches" they support.
Also, unlike many other programming languages, all conditionals in Common Lisp are expressions not statements. This means that all Lisp conditionals evaluate to some value and can be substituted for concrete parameters.
As an example:
;; Doubles x when it's even
(* x (if (evenp x) 2 1))
The conditionals when
and unless
evaluate some code only when the provided test is true or false respectively – evaluating to nil
otherwise.
The section after the test expression may be more than one expression.
(when (= 2 2) "All is well") ; => "All is well"
(unless (= 2 2) "Time to panic!") ; => NIL
The if
conditional evaluates the first expression of the body when the test is true and the second one otherwise.
(if (= 2 2) 'how-honest 'you-liar) ; => HOW-HONEST
Note that both the then and else clauses can only be a single expression.
The Lisp "super-conditional" is cond
, which can have an infinite number of branches.
Each branch has a test condition and body expression that are surrounded by an extra pair of parentheses.
If all of the tests evaluate to false, then nil
is returned.
(cond ((= 0 2) 'nope)
((= 1 2) 'try-again)
((= 2 2) 'quite-true)
((= 3 2) 'too-far)
(t 'something-else))
; => QUITE-TRUE
Note that there is no limit to the number of expressions after the test expression.
If you just want to test one value against a number of branches, you can use the cleaner case
expression.
If none of the cases match, nil
is returned.
Both t
and otherwise
can be used as catch-all cases:
(case 'elder-beast
(cat "Meow")
(bird "Chirp")
(dog "Bark")
(otherwise "???"))
; => "???"
Note that like cond
there is no limit to the number of expressions after the test expression.
The boolean and
and or
operations in Common Lisp are short-circuiting macros that can be used to reduce the duplication of certain conditional expressions.
The and
macro will immediately return nil
if a single false value is encountered, but the last true value of the and
otherwise:
(and 42 "Magic" :cool) ; => :COOL
(and () "Magic" :cool) ; => NIL
The or
macro returns the first true value it encounters or nil
if there were no true values:
(or () 42 nil) ; => 42
(or () NIL nil) ; => NIL
As mentioned previously, when none of the branches in a case
statement match, and there is no otherwise
clause, nil
is returned.
Occasionally, however, a failure to match any branch should be treated as an error – this is where ecase
(for exhaustive matching) comes in.
It's used in exactly the same way as case
, but signals an error instead of returning nil
when there is no match.
(case 'elder-beast
(cat "Meow")
(bird "Chirp")
(dog "Bark"))
; => NIL
(ecase 'elder-beast
(cat "Meow")
(bird "Chirp")
(dog "Bark"))
; => ERROR: ELDER-BEAST fell through ECASE expression. Wanted one of (CAT BIRD DOG).