Music 220b: Winter 2001
Fernando Lopez-Lezcano, instructor
Christopher Burns, teaching assistant
Tamara Smyth, teaching assistant

Week 2: logic - (if) and (cond)

We often want our lisp programs to make decisions. For instance, we might generate (with-sound) calls using a list of frequencies, and use different instruments depending upon the frequency. Or, we might analyze a soundfile, and take different actions depending upon the maximum amplitudes in a particular region.

In order to do these kinds of things, we need logical tests. Lisp provides two commands for this purpose: (if) and (cond).

• (if)

The body of an if statement has three sections, quickly summarized as "if," "then," and "else." In full syntax:

(if (test-clause)
(then-clause)
(else-clause))

For instance, "if the current frequency is greater than 440, generate a sound from fm-violin; else generate a sound from grani." Try -

CM(1): :cl /zap/v
CM(2): :cl /zap/grani
CM(3): (setf frequency 450)
CM(4): (with-sound (:statistics t :srate 44100)
(if (> frequency 440)
(fm-violin 0 1 frequency 0.3)
(grani 0 1 0.3 "/zap/cencerros-1.snd")))

For a more simple example, "if the frequency list has more than five elements, print a warning, otherwise return t [true]":

CM(8): (setf frequency-list (list 440 220 660 110 880 330))
CM(9): (if (> (length frequency-list) 5)
(format t "frequency list is too long....")
t)
frequency list is too long....
NIL

CM(13): (setf frequency-list (list 440 220))
CM(14): (if (> (length frequency-list) 5)
(format t "frequency list is too long....")
t)
T

This kind of test is often usefully expressed as a function:

(defun check-frequency-list-length (frequency-list)
(if (> (length frequency-list) 5)
(format t "frequency list is too long....")
t))

• (cond)

Cond is a more generic logic test than if; it allows you to specify many different conditions, instead of just one. This first example squares positive numbers, and returns the negative square of a negative number. In any other case it returns zero. ("t" automatically evaluates to true -- the equivalent of our else condition in the (if) statement).

(defun cond-example (number)
(cond ((> number 0) (* number number))
((< number 0) (- (* number number)))
(t 0)))

CM(18): (cond-example 3)
9
CM(19): (cond-example -3)
-9
CM(20): (cond-example 0)
0

In case the example doesn't make it clear, the cond syntax works like this:

(cond ((test-1) (do-this-if-test-1-is-true))
((test-2) (do-this-if-test-2-is-true))
...arbitrary number of tests...
((test-n) (do-this-if-test-n-is-true))
(t (do-this-if-all-tests-fail)))

Note that the tests are evaluated sequentially -- the interpreter tries test-2 only if test-1 fails. This means that the order of the tests are important.

So far we've only seen the simplest applications of if and cond; but they are the building blocks of far more complicated programs. Let your imagination run wild....