let, let*
let ({var | (var [init-form])}*) {declaration}* {form}* → {result}*
let* ({var | (var [init-form])}*) {declaration}* {form}* → {result}*
!!! Barmar thinks this should say "non-constant symbol".var—a symbol.
fixed some confusion about whether this is ``init-form'' or ``value''. --sjl 5 Mar 92init-form—a form.
!!! Barmar asks why "not evaluated" is only specified for this argument.
7.5.0 6
7.5.0 10declaration—a declare expression; not evaluated.
form—a form.
results—the values returned by the forms.
7.5.0 3let and let* create new variable bindings and execute a series of forms that use these bindings. let performs the bindings in parallel and let* does them sequentially.
7.5.0 4 7.5.0 5The form
(let ((var1 init-form-1)
(var2 init-form-2)
...
(varm init-form-m))
declaration1
declaration2
...
declarationp
form1
form2
...
formn)
first evaluates the expressions init-form-1, init-form-2, and so on, in that order, saving the resulting values. Then all of the variables varj are bound to the corresponding values; each binding is lexical unless there is a special declaration to the contrary. The expressions formk are then evaluated in order; the values of all but the last are discarded (that is, the body of a let is an implicit progn).
7.5.0 7
7.5.0 9let* is similar to let, but the bindings of variables are performed sequentially rather than in parallel. The expression for the init-form of a var can refer to vars previously bound in the let*.
7.5.0 8The form
(let* ((var1 init-form-1)
(var2 init-form-2)
...
(varm init-form-m))
declaration1
declaration2
...
declarationp
form1
form2
...
formn)
first evaluates the expression init-form-1, then binds the variable var1 to that value; then it evaluates init-form-2 and binds var2, and so on. The expressions formj are then evaluated in order; the values of all but the last are discarded (that is, the body of let* is an implicit progn).
For both let and let*, if there is not an init-form associated with a var, var is initialized to nil.
This is a property of TYPE declarations and doesn't need to be said again here. --sjl 5 Mar 92 The consequences are undefined if a type \param{declaration} is supplied for a \param{var} and the initial \param{value} of that \param{var} is not consistent with the type \param{declaration}.
The special form let has the property that the scope of the name binding does not include any initial value form. For let*, a variable's scope also includes the remaining initial value forms for subsequent variable bindings.
New name bindings take precedence over any higher level binding or declarations. For example, \code (locally (declare (special x) (float y)) (let ((x 5) (y 10)) (print (+ x y)))) \endcode If there are no proclamations are in effect, then {\tt x} is local (not \declref{special}) and {\tt y} is bound with no particular type information because the {\tt y} being bound is a different variable from the {\tt y} declared {\tt float}.
See \misc{declare}.
This is adequately addressed in the packages chapter. --sjl 5 Mar 92 \issue{LISP-SYMBOL-REDEFINITION:MAR89-X3J13} It is permissible to use symbols in \thepackage{common-lisp} as lexical variable names, provided they are not globally defined as \term{variables}. \endissue{LISP-SYMBOL-REDEFINITION:MAR89-X3J13}
(setq a 'top) → TOP
(defun dummy-function () a) → DUMMY-FUNCTION
(let ((a 'inside) (b a))
(format nil "~S ~S ~S" a b (dummy-function))) → "INSIDE TOP TOP"
(let* ((a 'inside) (b a))
(format nil "~S ~S ~S" a b (dummy-function))) → "INSIDE INSIDE TOP"
(let ((a 'inside) (b a))
(declare (special a))
(format nil "~S ~S ~S" a b (dummy-function))) → "INSIDE TOP INSIDE"
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 initially takes on the value nil in violation of the type declaration.
None.
None.
None.