lambdaand Lexical Scope (Hunk M)
================================================================== Hunk M starts here: ==================================================================
lambda creates a procedure that will execute in the
scope where the
lambda expression was evaluated.
Except for local variables of the procedure itself, including
its arguments, names in the body of the procedure refer to whatever
they refer to at the point where the procedure is created by
This is necessary for preserving lexical scope--the meanings of variable names must be obvious at the point where the procedure is defined.
Local variables created by the procedure have the usual scope rule within the body. (Argument variables are just a special kind of local variable, which get their initial values from the caller.) Other variables are called free variables--that is variables defined outside the procedure, but referred to from inside it.
We say that
lambda creates a closure, a procedure
whose free variable references are "fixed" at the time the procedure
is created. Whenever the procedure references a free variable, it
will will refer to the bindings of those variables in the environment
where the procedure was created.
Consider the following small program
(define foo 1) (define (baz) foo) (define (quux) (let ((foo 6)) (baz))) (quux)
quux is called, it will bind its local variable
and then call
baz is called from
however, it will still see the top level binding of
1. The result of the call to
baz will be
1, and that value will be returned as the value of the call to
quux as well.
There is a very good reason for this, and it's the rule used by most
programming languages. It is important that the meaning of a
procedure be fixed where it is defined, rather than having the
meaning depend on where it is called from. You want to be able to
look at the code, and see that the name
foo refers to particular
variable, namely the one that's visible there, at the top level.
You don't want to have to worry about the meaning of the procedure
baz changing, depending on where it's called from.
A block structure diagram may make this clearer. I'll just show the
part for the procedure
(define (quux) (let ((foo 6)) +---------------------------+ | (baz) scope of foo | )) +---------------------------+
This emphasizes the fact that the local
foo really is local.
The definition of
baz is not inside the box, so it can't
foo's local variable
foo. (The fact that
baz is called from inside the box doesn't matter.)
Conceptually, the procedure
baz returns to the environment
where it was created before it executes, and even before it binds its
In early Lisps, a different rule was used, called dynamic scope.
In those Lisps, the call to
baz would see the most
recent binding of
foo. In this case, it would see the
binding created by
quux just before the call to
This led to very inscrutable bugs, because a procedure would work
sometimes, and not others, depending on the names of variables
bound in other procedures.
(Dynamic scoping is generally considered to have been a big mistake, and was fixed in recent versions of Lisp, such as Common Lisp, which were influenced by Scheme.)