next up previous
Contents Next: More Predicates and Up: Conditional Control Previous: If


If is useful, but sometimes one would like to have multiple branching conditions. E.g. if condition A is met then do B, but if condition A is not met but condition C is met, then do D, but if neither condition A nor C is met then do E. This could be coded using if as follows (schematically):

(if A B (if C D E))

This is not too bad. But things can get a lot worse if you want to have a long chain of test conditions.

Lisp provides a very convenient macro called cond for such situations. The general form of a cond statement is as follows:

(cond (<testa>  <form1a>  <form2a>  ... <resulta> )
      (<testb>  <form1b>  <form2b>  ... <resultb> )
      (<testk>  <form1k>  <form2k>  ... <resultk> ))
We will call each of the lines (<test> .....<result> ) a ``cond clause'', or sometimes just ``clause'' for short. In cond clauses, only the test is required, but most commonly cond clauses contain just two elements: test and result.

Instead of nesting if statements as before, the set of conditions (if A B (if C D E)) can be expressed using cond. It would look like this:

(cond (A B)
      (C D)
      (t E))
A through E can be any Lisp expressions at all. If the evaluation of the test expression at the beginning of a clause returns nil, then the rest of the clause is not evaluated. If the test returns a non-nil value, all the other expressions in that clause are evaluated, and the value of the last one is returned as the value of the entire cond statement. (The intermediate forms are, therefore, only useful for producing side-effects. It is common to put t as the test for the last clause since this means that the last clause always will act as a default if none of the other tests succeed.

Here's a simple example, using cond instead of if, defining absdiff to act as before:

(defun absdiff (x y)
  (cond ((>  x y) (- x y))
        (t (- y x))))
Notice the double left parenthesis immediately following cond in this example. A common beginner's programming error is to omit one of these, but both are required since the test in this cond clause is (> x y). With just one parenthesis, the cond statement would attempt to treat the symbol > as the test, which would result in an unbound variable error. Conversely, there is only one left parenthesis in front of the t in the second clause. Again, the explanation is that the test is to evaluate the constant t.

Cond and if statements are most powerful in defining functions that must repeat some step or steps a number of times. In the next chapter, you will see how cond and if are essential for giving recursive function definitions which exploit the power of Lisp to solve repetitive problems. Before we can exploit that potential, it will be necessary to learn some more commonly used predicates and functions, that serve well as test statements.

next up previous
Contents Next: More Predicates and Up: Conditional Control Previous: If

© Colin Allen & Maneesh Dhagat
March 2007