lets define variables by the same name, then the
uses of that name in the body of the inner
let will refer to the
bindings created by the inner
Consider the following code fragment:
(let ((x 10) ; outer binding of x (a 20)) ; binding of a (foo x) (let ((x (bar)) ; inner binding of x (b (baz x x))) ; binding of b (quux x a) (quux y b)) (baz x a) ; refers to outer x (and a) (baz x b)) ; illegal?
When control enters the outer
let, the inital values for the
variables are computed. In this case, that's just the literal values
20. Then storage is allocated for the variables,
and initialized with those values. Once that's done, the meaning of
a changes--they now refer to the new
storage for (bindings of) the
a---and then the body expressions are evaluated.
Similarly, when control enters the inner
let, the inital values
are computed by the calls to
baz, and then
b is allocated and initialized with
those values. Then the meanings of the names
change, to refer to the new storage (bindings) of those variables.
(For example, the value of
(baz x x) is evaluated
is still 10, because
x still refers to the outer
In this example, the meaning of the identifier
x changes when
we enter the inner
let. We say that the inner let variable
x shadows the outer one, within the body of the
x is no longer visible, because the inner one is.
When we exit a
let (after evaluating its body expressions), the
bindings introduced by the
let "go out of scope," i.e., aren't visible
anymore. (For example, when we evaluate the expression
(baz x a)
in the body of the outer
x refers to the binding
introduced by the outer
x introduced by the
inner let is no longer visible.
Likewise, in the example code fragment, the
b in the last
(baz x b), does not refer to the inner
b. Unless there is a binding of
b in some
outer scope we haven't shown (such as a top-level binding), then
this will be an error.