In most procedural programming languages, you can write a sequence of
if tests using an extended version of
if, something like
if test1 then action1(); else if test2 then action2(); else if test3 then action3(); else action4();
Scheme has a similar construct, a special form called
above example might be written in Scheme as
(cond (test1 (action1)) (test2 (action2)) (test3 (action3)) (else (action4)))
Notice that each test-and-action pair is enclosed in parentheses. In
test1 is just a variable reference, not a procedure
call, i.e., we're testing to see if the value of the variable
#f; if not, we'll execute
(action1), i.e., call the procedure
action1. If it is false, control "falls through" to the next
test, and keeps going until one of the tests evaluates to a true
value (anything but
Notice that we indent the actions corresponding to a test by one character. This lines the actions up directly under the tests, rather than under the opening parenthesis that groups them together.
else clause of a
cond is optional; if present,
that branch will be taken "by default"---if none of the other
conditions evaluates to a true value, the
else branch will
We don't really need the else clause, because we could get the same
effect by using a test expression that always evaluates to a true
value. One way of doing this is to use the literal
#t, the true
boolean, because it's always true.
(cond (test1 (action1)) (test2 (action2)) (test3 (action3)) (#t ; literal #t is always true, so (action4))) ; this branch is taken if we get this far
The code above is equivalent to a nested set of
(if test1 (action1) (if test2 (action2) (if test3 (action3) (if #t (action4)))))
cond returns the value of whatever "branch"
it executes. If
test1 is true, for example, the above
will return the value returned from the procedure call
Remember that each branch of an
if is a single expression;
if you want to execute more than one expression in a branch,
you have to wrap the expressions in a
you don't have to do this. You can follow a test expression with more
than one action expression, and Scheme will evaluate all of them,
in order, and return the value of the last one, just like a
or a procedure body.
Suppose we want to modify the above
cond example so that it
prints out the branch it's taking, as well as evaluating the action
expression and returning its value. We can do this:
(cond (test1 (display "taking first branch") (action1)) (test2 (display "taking second branch") (action2)) (test3 (display "taking third branch") (action3)) (else (display "taking fourth (default) branch") (action4)))
cond will return the same value as the original, because
it always returns the value of the last expression in a branch. As
it executes, however, it also displays what it's doing. We can use
cond both for value and for effect.
Be particularly careful about parentheses with
must enclose each branch with a pair of parentheses around the test
expression and the corresponding sequence of action expressions. If
you want to call a procedure in any of those expressions, you must
also put parentheses around the procedure call. In the above
example, if we wanted the first test to be a call to a procedure
test1---rather than just fetching the value of the variable
(cond ((test1) (display "taking first branch") (action1)) ...)
(cond (test1 (display "taking first branch") (action1)) ...)
(Note the indenting here. We usually line up a test and the corresponding sequence of actions vertically, whether or not the expression starts with a parentheses. That is, we indent one space past the opening parenthesis of the pair of parentheses that goes around them all.)
The "extra" parentheses are necessary so that
tell which action sequences are grouped with which tests.
Don't be afraid to use
cond for conditionals with only one
or two branches.
cond is often more convenient than
because it can execute a sequence of expressions, instead of just
one. It's not uncommon to see things like this:
... (cond ((foo) (bar) (baz))) ...
Don't be confused by this--there's only one branch to this
like a one-branch
if. We could have written it
... (if (foo) (begin (bar) (baz))) ...
It's just more convenient to use
so that we can call
bar before calling
baz and returning
its result, without explicitly writing a
to sequence them.
We say that
cond is syntactic sugar for nested
begins around the branches. There's nothing we can do
cond that we can't do straightforwardly with
cond just gives us a "sweetened" syntax,
i.e., one that's more convenient.
Most of the special forms in Scheme are like this--they're just a convenient way of writing things that you could write using more basic special forms. (There are only five "core" special forms that are really necessary, and the others are equivalent to combinations of those special forms.)