Common LISP Hints: Booleans and Conditionals

## 17. Booleans and Conditionals

LISP uses the self-evaluating symbol `nil` to mean false. Anything other than `nil` means true. Unless we have a reason not to, we usually use the self-evaluating symbol `t` to stand for true.

LISP provides a standard set of logical functions, for example `and`, `or`, and `not`. The `and` and `or` connectives are short-circuiting: and will not evaluate any arguments to the right of the first one which evaluates to `nil`, while `or` will not evaluate any arguments to the right of the first one which evaluates to `t` (with `t` we mean here ``non-`nil`'').

LISP also provides several special forms for conditional execution. The simplest of these is `if`. The first argument of `if` determines whether the second or third argument will be executed:

> `

>     > (if t 5 6)
>     5
>     > (if nil 5 6)
>     6
>     > (if 4 5 6)
>     5

> `

If you need to put more than one statement in the then or else clause of an if statement, you can use the `progn` special form. `Progn` executes each statement in its body, then returns the value of the final one.

> `

>     > (setq a 7)
>     7
>     > (setq b 0)
>     0
>     > (setq c 5)
>     5
>     > (if (> a 5)
>         (progn
>           (setq a (+ b 7))
>           (setq b (+ c 8)))
>         (setq b 4))
>     13

> `

An `if` statement which lacks either a then or an else clause can be written using the `when` or `unless` special form:

> `

>     > (when t 3)
>     3
>     > (when nil 3)
>     NIL
>     > (unless t 3)
>     NIL
>     > (unless nil 3)
>     3

> `

`When` and `unless`, unlike `if`, allow any number of statements in their bodies. (Eg, `(when x a b c)` is equivalent to `(if x (progn a b c))`.)

> `

>     > (when t
>         (setq a 5)
>         (+ a 6))
>     11

> `

More complicated conditionals can be defined using the `cond` special form, which is equivalent to an if ... else if ... fi construction.

A `cond` consists of the symbol `cond` followed by a number of cond clauses, each of which is a list. The first element of a cond clause is the condition; the remaining elements (if any) are the action. The cond form finds the first clause whose condition evaluates to true (ie, doesn't evaluate to nil); it then executes the corresponding action and returns the resulting value. None of the remaining conditions are evaluated; nor are any actions except the one corresponding to the selected condition. For example:

> `

>     > (setq a 3)
>     3
>     > (cond
>        ((evenp a) a)        ;if a is even return a
>        ((> a 7) (/ a 2))    ;else if a is bigger than 7 return a/2
>        ((< a 5) (- a 1))    ;else if a is smaller than 5 return a-1
>        (t 17))              ;else return 17
>     2

> `

If the action in the selected cond clause is missing, `cond` returns what the condition evaluated to:

> `

>     > (cond ((+ 3 4)))
>     7

> `

Here's a clever little recursive function which uses `cond`. You might be interested in trying to prove that it terminates for all integers `x` at least 1. (If you succeed, please publish the result.)

> `

>     > (defun hotpo (x steps)        ;hotpo stands for Half Or Triple Plus One
>         (cond
>          ((= x 1) steps)
>          ((oddp x) (hotpo (+ 1 (* x 3)) (+ 1 steps)))
>          (t (hotpo (/ x 2) (+ 1 steps)))))
>     A
>     > (hotpo 7 0)
>     16

> `

The LISP case statement is like a C switch statement:

> `

>     > (setq x 'b)
>     B
>     > (case x
>        (a 5)
>        ((d e) 7)
>        ((b f) 3)
>        (otherwise 9))
>     3

> `

The otherwise clause at the end means that if `x` is not `a`, `b`, `d`, `e`, or `f`, the case statement will return 9.