Previous Next Contents

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)
> (if nil 5 6)
> (if 4 5 6)

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)
> (setq b 0)
> (setq c 5)
> (if (> a 5)
      (setq a (+ b 7))
      (setq b (+ c 8)))
    (setq b 4))

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)
> (when nil 3)
> (unless t 3)
> (unless nil 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))

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)
> (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

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

> (cond ((+ 3 4)))

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
     ((= x 1) steps)
     ((oddp x) (hotpo (+ 1 (* x 3)) (+ 1 steps)))
     (t (hotpo (/ x 2) (+ 1 steps)))))
> (hotpo 7 0)

The LISP case statement is like a C switch statement:

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

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

Previous Next Contents