Common Lisp the Language, 2nd Edition
Next: Conditionals
Up: Control Structure
Previous: Simple
Sequencing
During the invocation of a function represented by a
lambda-expression (or a closure of a lambda-expression, as produced by
function
), new bindings are established for the variables
that are the parameters of the lambda-expression. These bindings
initially have values determined by the parameter-binding protocol
discussed in section 5.2.2.
The following constructs may also be used to establish bindings of variables, both ordinary and functional.
[Special Form]
let
({
var
|
(
var value
)}*)
{
declaration
}*
{
form
}*
A let
form can be used to execute a series of forms with
specified variables bound to specified values.
More precisely, the form
(let ((var1 value1)
(var2 value2)
...
(varm valuem))
declaration1
declaration2
...
declarationp
body1
body2
...
bodyn)
first evaluates the expressions value1, value2, and
so on, in that order, saving the resulting values. Then all of the
variables varj are bound to the corresponding values in
parallel; each binding will be a lexical binding unless there is a
special
declaration to the contrary. The expressions
bodyk are then evaluated in order; the values of all but the
last are discarded (that is, the body of a let
form is an
implicit progn
). The let
form returns what
evaluating bodyn produces (if the body is empty, which is
fairly useless, let
returns nil
as its value).
The bindings of the variables have lexical scope and indefinite
extent.
Instead of a list
(
varj
valuej
)
,
one may write simply varj. In this case varj is
initialized to nil
. As a matter of style, it is recommended
that varj be written only when that variable will be stored
into (such as by setq
) before its first use. If it is
important that the initial value be nil
rather than some
undefined value, then it is clearer to write out
(
varj
``nil``)
if the
initial value is intended to mean ``false,’’ or
(
varj
'``()``)
if the
initial value is intended to be an empty list. Note that the code
(let (x)
(declare (integer x))
(setq x (gcd y z))
...)
is incorrect; although x
is indeed set before it is
used, and is set to a value of the declared type integer
,
nevertheless x
momentarily takes on the value
nil
in violation of the type declaration.
Declarations may appear at the beginning of the body of a
let
. See declare
.
See also destructuring-bind
.
X3J13 voted in January 1989 (VARIABLE-LIST-ASYMMETRY) to regularize
the binding formats for do
, do*
,
let
, let*
, prog
,
prog*
, and compiler-let
. The new syntactic
definition for let
makes the value optional:
[Special Form]
let
({
var
|
(
var
[
value
])}*)
{
declaration
}*
{
form
}*
This changes let
to allow a list
(
var
)
to appear, meaning
the same as simply var.
[Special Form]
let*
({
var
|
(
var value
)}*)
{
declaration
}*
{
form
}*
let*
is similar to let
, but the bindings of
variables are performed sequentially rather than in parallel. This
allows the expression for the value of a variable to refer to variables
previously bound in the let*
form.
More precisely, the form
(let* ((var1 value1)
(var2 value2)
...
(varm valuem))
declaration1
declaration2
...
declarationp
body1
body2
...
bodyn)
first evaluates the expression value1, then binds the
variable var1 to that value; then it evaluates value2
and binds var2; and so on. The expressions bodyj are
then evaluated in order; the values of all but the last are discarded
(that is, the body of a let*
form is an implicit
progn
). The let*
form returns the results of
evaluating bodyn (if the body is empty, which is fairly
useless, let*
returns nil
as its value). The
bindings of the variables have lexical scope and indefinite extent.
Instead of a list
(
varj
valuej
)
,
one may write simply varj. In this case varj is
initialized to nil
. As a matter of style, it is recommended
that varj be written only when that variable will be stored
into (such as by setq
) before its first use. If it is
important that the initial value be nil
rather than some
undefined value, then it is clearer to write out
(
varj
``nil``)
if the
initial value is intended to mean ``false,’’ or
(
varj
'``()``)
if the
initial value is intended to be an empty list.
Declarations may appear at the beginning of the body of a
let*
. See declare
.
X3J13 voted in January 1989 (VARIABLE-LIST-ASYMMETRY) to regularize
the binding formats for do
, do*
,
let
, let*
, prog
,
prog*
, and compiler-let
. The new syntactic
definition for let*
makes the value optional:
[Special Form]
let*
({
var
|
(
var
[
value
])}*)
{
declaration
}*
{
form
}*
This changes let*
to allow a list
(
var
)
to appear, meaning
the same as simply var.
[Special Form]
compiler-let
({
var
|
(
var
value
)}*)
{
form
}*
When executed by the Lisp interpreter, compiler-let
behaves exactly like let
with all the variable bindings
implicitly declared special
. When the compiler processes
this form, however, no code is compiled for the bindings; instead, the
processing of the body by the compiler (including, in particular, the
expansion of any macro calls within the body) is done with the special
variables bound to the indicated values in the execution context of
the compiler. This is primarily useful for communication among
complicated macros.
Declarations may not appear at the beginning of the body of
a compiler-let
.
Rationale: Because of the unorthodox handling by
compiler-let
of its variable bindings, it would be
complicated and confusing to permit declarations that apparently
referred to the variables bound by compiler-let
.
Disallowing declarations eliminates the problem.
X3J13 voted in January 1989 (VARIABLE-LIST-ASYMMETRY) to regularize
the binding formats for do
, do*
,
let
, let*
, prog
,
prog*
, and compiler-let
. The new syntactic
definition for compiler-let
makes the value
optional:
[Macro]
compiler-let
({
var
|
(
var
[
value
])}*)
{
form
}*
This changes compiler-let
to allow a list
(
var
)
to appear, meaning
the same as simply var.
X3J13 voted in June 1989 (COMPILER-LET-CONFUSION) to remove
compiler-let
from the language. Many uses of
compiler-let
can be replaced with more portable code that
uses macrolet
or symbol-macrolet
.
[Special Form]
progv
symbols
values
{
form
}*
progv
is a special form that allows binding one or more
dynamic variables whose names may be determined at run time. The
sequence of forms (an implicit progn
) is evaluated with the
dynamic variables whose names are in the list symbols bound to
corresponding values from the list values. (If too few values
are supplied, the remaining symbols are bound and then made to have no
value; see makunbound
. If too many values are supplied, the
excess values are ignored.) The results of the progv
form
are those of the last form. The bindings of the dynamic
variables are undone on exit from the progv
form. The lists
of symbols and values are computed quantities; this is what makes
progv
different from, for example, let
, where
the variable names are stated explicitly in the program text.
progv
is particularly useful for writing interpreters
for languages embedded in Lisp; it provides a handle on the mechanism
for binding dynamic variables.
[Special Form]
flet ({(name lambda-list
[[ {declaration}* | doc-string ]] {form}*)}*)
{form}*
labels ({(name lambda-list
[[ {declaration}* | doc-string ]] {form}*)}*)
{form}*
macrolet ({(name varlist
[[ {declaration}* | doc-string ]] {form}*)}*)
{form}*
flet
may be used to define locally named functions.
Within the body of the flet
form, function names matching
those defined by the flet
refer to the locally defined
functions rather than to the global function definitions of the same
name.
Any number of functions may be simultaneously defined. Each
definition is similar in format to a defun
form: first a
name, then a parameter list (which may contain
&optional
, &rest
, or
&key
parameters), then optional declarations and
documentation string, and finally a body.
(flet ((safesqrt (x) (sqrt (abs x))))
;; The safesqrt function is used in two places.
(safesqrt (apply #'+ (map 'list #'safesqrt longlist))))
The labels
construct is identical in form to the
flet
construct. These constructs differ in that the scope
of the defined function names for flet
encompasses only the
body, whereas for labels
it encompasses the function
definitions themselves. That is, labels
can be used to
define mutually recursive functions, but flet
cannot. This
distinction is useful. Using flet
one can locally redefine
a global function name, and the new definition can refer to the global
definition; the same construction using labels
would not
have that effect.
(defun integer-power (n k) ;A highly "bummed" integer
(declare (integer n)) ; exponentiation routine
(declare (type (integer 0 *) k))
(labels ((expt0 (x k a)
(declare (integer x a) (type (integer 0 *) k))
(cond ((zerop k) a)
((evenp k) (expt1 (* x x) (floor k 2) a))
(t (expt0 (* x x) (floor k 2) (* x a)))))
(expt1 (x k a)
(declare (integer x a) (type (integer 1 *) k))
(cond ((evenp k) (expt1 (* x x) (floor k 2) a))
(t (expt0 (* x x) (floor k 2) (* x a))))))
(expt0 n k 1)))
macrolet
is similar in form to flet
but
defines local macros, using the same format used by
defmacro
. The names established by macrolet
as
names for macros are lexically scoped.
I have observed that, while most Common Lisp users pronounce
macrolet
to rhyme with ``silhouette,’’ a small but vocal
minority pronounce it to rhyme with ``Chevrolet.’’ A very few extremists
furthermore adjust their pronunciation of flet
similarly:
they say ``flay.’’ Hey, hey! Très outré.
Macros often must be expanded at ``compile time’’ (more generally, at
a time before the program itself is executed), and so the run-time
values of variables are not available to macros defined by
macrolet
.
The precise rule is that the macro-expansion functions defined by
macrolet
are defined in the global environment;
lexically scoped entities that would ordinarily be lexically apparent
are not visible within the expansion functions.
X3J13 voted in March 1989 (DEFINING-MACROS-NON-TOP-LEVEL) to retract
the previous sentence and specify that the macro-expansion functions
created by macrolet
are defined in the lexical environment
in which the macrolet
form appears, not in the null lexical
environment. Declarations, macrolet
definitions, and
symbol-macrolet
definitions affect code within the
expansion functions in a macrolet
, but the consequences are
undefined if such code attempts to refer to any local variable or
function bindings that are visible in that lexical environment.
However, lexically scoped entities are visible within the
body of the macrolet
form and are visible to the
code that is the expansion of a macro call. The following example should
make this clear:
;;; Example of scoping in macrolet.
(defun foo (x flag)
(macrolet ((fudge (z)
;;The parameters x and flag are not accessible
;; at this point; a reference to flag would be to
;; the global variable of that name.
`(if flag
(* ,z ,z)
,z)))
;;The parameters x and flag are accessible here.
(+ x
(fudge x)
(fudge (+ x 1)))))
The body of the macrolet
becomes
(+ x
(if flag
(* x x)
x))
(if flag
(* (+ x 1) (+ x 1))
(+ x 1)))
after macro expansion. The occurrences of x
and
flag
legitimately refer to the parameters of the function
foo
because those parameters are visible at the site of the
macro call which produced the expansion.
X3J13 voted in March 1988 (FLET-IMPLICIT-BLOCK) to specify that the
body of each function or expander function defined by flet
,
labels
, or macrolet
is implicitly enclosed in
a block
construct whose name is the same as the
name of the function. Therefore return-from
may be
used to exit from the function.
X3J13 voted in March 1989 (FUNCTION-NAME) to extend
flet
and labels
to accept any function-name (a
symbol or a list whose car is setf
-see section 7.1) as a name for a
function to be locally defined. In this way one can create local
definitions for setf
expansion functions. (X3J13 explicitly
declined to extend macrolet
in the same manner.)
X3J13 voted in March 1988 (FLET-DECLARATIONS) to change
flet
, labels
, and macrolet
to
allow declarations to appear before the body. The new descriptions are
therefore as follows:
[Special Form]
flet ({(name lambda-list
[[ {declaration}* | doc-string ]] {form}*)}*)
{declaration}* {form}*
labels ({(name lambda-list
[[ {declaration}* | doc-string ]] {form}*)}*)
{declaration}* {form}*
macrolet ({(name varlist
[[ {declaration}* | doc-string ]] {form}*)}*)
{declaration}* {form}*
These are now syntactically more similar to such other binding forms
as let
.
For flet
and labels
, the bodies of the
locally defined functions are part of the scope of pervasive
declarations appearing before the main body. (This is consistent with
the treatment of initialization forms in let
.) For
macrolet
, however, the bodies of the locally defined macro
expander functions are not included in the scope of pervasive
declarations appearing before the main body. (This is consistent with
the rule, stated below, that the bodies of macro expander functions are
in the global environment, not the local lexical environment.) Here is
an example:
(flet ((stretch (x) (* x *stretch-factor*))
(chop (x) (- x *chop-margin*)))
(declare (inline stretch chop)) ;Illegal in original Common Lisp
(if (> x *chop-margin*) (stretch (chop x)) (chop (stretch x))))
X3J13 voted to permit declarations of the sort noted above.
[Special Form]
symbol-macrolet ({(var expansion)}*)
{declaration}* {form}*
X3J13 voted in June 1988 (CLOS) to adopt the Common Lisp Object
System. Part of this proposal is a general mechanism,
symbol-macrolet
, for treating certain variable names as if
they were parameterless macro calls. This facility may be useful
independent of CLOS. X3J13 voted in March 1989
(SYMBOL-MACROLET-SEMANTICS) to modify the definition of
symbol-macrolet
substantially and also voted
(SYMBOL-MACROLET-DECLARE) to allow declarations before the body of
symbol-macrolet
but with peculiar treatment of
special
and type declarations.
The forms are executed as an implicit progn
in
a lexical environment that causes every reference to any defined
var to be replaced by the corresponding expansion. It
is as if the reference to the var were a parameterless macro
call; the expansion is evaluated or otherwise processed in
place of the reference (in particular, the expansion form is itself
subject to further expansion-this is one of the changes
(SYMBOL-MACROLET-SEMANTICS) from the original definition in the CLOS
proposal). Note, however, that the names of such symbol macros occupy
the name space of variables, not the name space of functions; just as
one may have a function (or macro, or special form) and a variable with
the same name without interference, so one may have an ordinary macro
(or function, or special form) and a symbol macro with the same name.
The use of symbol-macrolet
can therefore be shadowed by
let
or other constructs that bind variables;
symbol-macrolet
does not substitute for all occurrences of
a var as a variable but only for those occurrences that would
be construed as references in the scope of a lexical binding of
var as a variable. For example:
(symbol-macrolet ((pollyanna 'goody))
(list pollyanna (let ((pollyanna 'two-shoes)) pollyanna)))
=> (goody two-shoes), not (goody goody)
One might think that 'goody
simply replaces all
occurrences of pollyanna
, and so the value of the
let
would be goody
; but this is not so. A
little reflection shows that under this incorrect interpretation the
body in expanded form would be
(list 'goody (let (('goody 'two-shoes)) 'goody))
which is syntactically malformed. The correct expanded form is
(list 'goody (let ((pollyanna 'two-shoes)) pollyanna))
because the rebinding of pollyanna
by the
let
form shadows the symbol macro definition.
The expansion for each var is not evaluated at
binding time but only after it has replaced a reference to the
var. The setf
macro allows a symbol macro to be
used as a place, in which case its expansion is used; moreover,
setq
of a variable that is really a symbol macro will be
treated as if setf
had been used. The values of the last
form are returned, or nil
if there is no value.
See macroexpand
and macroexpand-1
; they
will expand symbol macros as well as ordinary macros.
Certain declarations before the body are handled in a
peculiar manner; see section 9.1.
Next: Conditionals
Up: Control Structure
Previous: Simple
Sequencing
AI.Repository@cs.cmu.edu