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 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....