The let
and let*
forms provide lexical scoping, which is what you
expect if you're used to programming in C or Pascal. Dynamic scoping is
what you get in BASIC: if you assign a value to a dynamically scoped
variable, every mention of that variable returns that value until you
assign another value to the same variable.
In LISP, dynamically scoped variables are called special variables. You can declare a special variable with the defvar special form. Here are some examples of lexically and dynamically scoped variables.
In this example, the function check-regular
references a regular (ie,
lexically scoped) variable. Since check-regular
is lexically outside of
the let
which binds regular
, check-regular
returns the
variable's global value.
> (set 'regular 5) ;setq would make it special in CMUCL!
5
> (defun check-regular () regular)
CHECK-REGULAR
> (check-regular)
5
> (let ((regular 6)) (check-regular))
5
In this example, the function check-special
references a special (ie,
dynamically scoped) variable. Since the call to check-special
is
temporally inside of the let
which binds special,
check-special
returns
the variable's local value.
> (defvar *special* 5)
*SPECIAL*
> (defun check-special () *special*)
CHECK-SPECIAL
> (check-special)
5
> (let ((*special* 6)) (check-special))
6
By convention, the name of a special variable begins and ends with a *. Special variables are chiefly used as global variables, since programmers usually expect lexical scoping for local variables and dynamic scoping for global variables.
For more information on the difference between lexical and dynamic scoping, see Common LISP: the Language.