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]
if
test
then
[
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]
when
test
{
form
}*
(when
test
form1
form2
... )
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]
unless
test
{
form
}*
(unless
test
form1
form2
... )
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 (values
x
)))
,
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