Common Lisp the Language, 2nd Edition
![]()
Next: Blocks and Exits
Up: Control Structure
Previous: Establishing New
Variable
The traditional conditional construct in Lisp is cond.
However, if is much simpler and is directly comparable to
conditional constructs in other programming languages, so it is
considered to be primitive in Common Lisp and is described first. Common
Lisp also provides the dispatching constructs case and
typecase, which are often more convenient than
cond.
[Special Form]
iftestthen[else]
The if special form corresponds to the
if-then-else
construct found in most algebraic programming languages. First the form
test is evaluated. If the result is not nil, then
the form then is selected; otherwise the form else is
selected. Whichever form is selected is then evaluated, and
if returns whatever is returned by evaluation of the
selected form.
(if test then else) == (cond (test then) (t else))
but if is considered more readable in some
situations.
The else form may be omitted, in which case if the value of
test is nil then nothing is done and the value of
the if form is nil. If the value of the
if form is important in this situation, then the
and construct may be stylistically preferable, depending on
the context. If the value is not important, but only the effect, then
the when construct may be stylistically preferable.
[Macro]
whentest{form}*
(whentestform1form2... )
first evaluates test. If the result is nil, then
no form is evaluated, and nil is returned.
Otherwise the forms constitute an implicit progn
and are evaluated sequentially from left to right, and the value of the
last one is returned.
(when p a b c) == (and p (progn a b c))
(when p a b c) == (cond (p a b c))
(when p a b c) == (if p (progn a b c) nil)
(when p a b c) == (unless (not p) a b c)
As a matter of style, when is normally used to
conditionally produce some side effects, and the value of the
when form is normally not used. If the value is relevant,
then it may be stylistically more appropriate to use and or
if.
[Macro]
unlesstest{form}*
(unlesstestform1form2... )
first evaluates test. If the result is not
nil, then the forms are not evaluated, and
nil is returned. Otherwise the forms constitute an
implicit progn and are evaluated sequentially from left to
right, and the value of the last one is returned.
(unless p a b c) == (cond ((not p) a b c))
(unless p a b c) == (if p nil (progn a b c))
(unless p a b c) == (when (not p) a b c)
As a matter of style, unless is normally used to
conditionally produce some side effects, and the value of the
unless form is normally not used. If the value is relevant,
then it may be stylistically more appropriate to use
if.
[Macro]
cond {(test{form}*)}*
A cond form has a number (possibly zero) of
clauses, which are lists of forms. Each clause consists of a
test followed by zero or more consequents. For
example:
(cond (test-1 consequent-1-1 consequent-1-2 ...)
(test-2)
(test-3 consequent-3-1 ...)
... )
The first clause whose test evaluates to
non-nil is selected; all other clauses are ignored, and the
consequents of the selected clause are evaluated in order (as an
implicit progn).
More specifically, cond processes its clauses in order
from left to right. For each clause, the test is evaluated. If
the result is nil, cond advances to the next
clause. Otherwise, the cdr of the clause is treated as a list
of forms, or consequents; these forms are evaluated in order from left
to right, as an implicit progn. After evaluating the
consequents, cond returns without inspecting any remaining
clauses. The cond special form returns the results of
evaluating the last of the selected consequents; if there were no
consequents in the selected clause, then the single (and necessarily
non-null) value of the test is returned. If cond
runs out of clauses (every test produced nil, and therefore
no clause was selected), the value of the cond form is
nil.
If it is desired to select the last clause unconditionally if all
others fail, the standard convention is to use t for the
test. As a matter of style, it is desirable to write a last
clause (``t`` ``nil``) if the value of the
cond form is to be used for something. Similarly, it is in
questionable taste to let the last clause of a cond be a
``singleton clause’’; an explicit t should be provided.
(Note moreover that
(cond ... (x)) may
behave differently from
(cond ... (``t``x)) if
x might produce multiple values; the former always returns a
single value, whereas the latter returns whatever values x
returns. However, as a matter of style it is preferable to obtain this
behavior by writing
(cond ... (t (valuesx))),
using the values function explicitly to indicate the
discarding of any excess values.) For example:
(setq z (cond (a 'foo) (b 'bar))) ;Possibly confusing
(setq z (cond (a 'foo) (b 'bar) (t nil))) ;Better
(cond (a b) (c d) (e)) ;Possibly confusing
(cond (a b) (c d) (t e)) ;Better
(cond (a b) (c d) (t (values e))) ;Better (if one value
; needed)
(cond (a b) (c)) ;Possibly confusing
(cond (a b) (t c)) ;Better
(if a b c) ;Also better
A Lisp cond form may be compared to a continued
if-then-else as found
in many algebraic programming languages:
(cond (p ...) if p then ...
(q ...) roughly else if q then ...
(r ...) corresponds else if r then ...
... to ...
(t ...)) else ...
[Macro]
case keyform
{({({key}*)
| key}
{form}*)}*
case is a conditional that chooses one of its clauses to
execute by comparing a value to various constants, which are typically
keyword symbols, integers, or characters (but may be any objects). Its
form is as follows:
(case keyform
(keylist-1 consequent-1-1 consequent-1-2 ...)
(keylist-2 consequent-2-1 ...)
(keylist-3 consequent-3-1 ...)
...)
Structurally case is much like cond, and it
behaves like cond in selecting one clause and then
executing all consequents of that clause. However, case
differs in the mechanism of clause selection.
The first thing case does is to evaluate the form
keyform to produce an object called the key object.
Then case considers each of the clauses in turn. If
key is in the keylist (that is, is eql to
any item in the keylist) of a clause, the consequents of that
clause are evaluated as an implicit progn;
case returns what was returned by the last consequent (or
nil if there are no consequents in that clause). If no
clause is satisfied, case returns nil.
The keys in the keylists are not evaluated; literal key
values must appear in the keylists. It is an error for the same key to
appear in more than one clause; a consequence is that the order of the
clauses does not affect the behavior of the case
construct.
Instead of a keylist, one may write one of the symbols
t and otherwise. A clause with such a symbol
always succeeds and must be the last clause (this is an exception to the
order-independence of clauses). See also ecase and
ccase, each of which provides an implicit
otherwise clause to signal an error if no clause is
satisfied.
If there is only one key for a clause, then that key may be written
in place of a list of that key, provided that no ambiguity results. Such
a ``singleton key’’ may not be nil (which is confusable
with (), a list of no keys), t,
otherwise, or a cons.
Compatibility note: The Lisp Machine Lisp
caseq construct uses eq for the comparison. In
Lisp Machine Lisp caseq therefore works for fixnums but not
bignums. The MacLisp caseq construct simply prohibits the
use of bignums; indeed, it permits only fixnums and symbols as clause
keys. In the interest of hiding the fixnum-bignum distinction, and for
general language consistency, case uses eql in
Common Lisp.
The Interlisp selectq construct is similar to
case.
[Macro]
typecase keyform
{(type
{form}*)}*
typecase is a conditional that chooses one of its
clauses by examining the type of an object. Its form is as follows:
(typecase keyform
(type-1 consequent-1-1 consequent-1-2 ...)
(type-2 consequent-2-1 ...)
(type-3 consequent-3-1 ...)
...)
Structurally typecase is much like cond or
case, and it behaves like them in selecting one clause and
then executing all consequents of that clause. It differs in the
mechanism of clause selection.
The first thing typecase does is to evaluate the form
keyform to produce an object called the key object. Then
typecase considers each of the clauses in turn. The
type that appears in each clause is a type specifier; it is not
evaluated but is a literal type specifier. The first clause for which
the key is of that clause’s specified type is selected, the
consequents of this clause are evaluated as an implicit
progn, and typecase returns what was returned
by the last consequent (or nil if there are no consequents
in that clause). If no clause is satisfied, typecase
returns nil.
As for case, the symbol t or
otherwise may be written for type to indicate that
the clause should always be selected. See also etypecase
and ctypecase, each of which provides an implicit
otherwise clause to signal an error if no clause is
satisfied.
It is permissible for more than one clause to specify a given type,
particularly if one is a subtype of another; the earliest applicable
clause is chosen. Thus for typecase, unlike
case, the order of the clauses may affect the behavior of
the construct. For example:
(typecase an-object
(string ...) ;This clause handles strings
((array t) ...) ;This clause handles general arrays
((array bit) ...) ;This clause handles bit arrays
(array ...) ;This handles all other arrays
((or list number) ...) ;This handles lists and numbers
(t ...)) ;This handles all other objects
A Common Lisp compiler may choose to issue a warning if a clause cannot be selected because it is completely shadowed by earlier clauses.
![]()
Next: Blocks and Exits
Up: Control Structure
Previous: Establishing New
Variable
AI.Repository@cs.cmu.edu