The set of all bindings that are visible at a given point during program execution is called a binding environment. That is, a binding environment maps a set of names to the pieces of storage they name.
A top-level binding environment is the mapping that the Scheme system maintains between top-level variable names and the storage they're bound to. This might be implemented as a hash table.
With local variables, a simple "flat" table isn't sufficient. Entering
a let
, for example, adds new bindings to the environment that code
is executing in--it makes the new variable bindings visible, changing
the mapping from names to storage.
We say that each binding construct we execute introduces a new binding contour. We call it a contour because it changes the "shape" of the environment.
You can think of a binding contour as being implemented by a new table
that's created when you enter a let
, or any other construct
that binds variables. When Scheme looks for a binding of an identifier,
it looks first in this new table, then in the old table that represented
the environment outside the let. Since Scheme looks in the
"inner" environment's table first, it will always find the innermost
binding of any identifier, such as x
in the example above.
At any given point, the environment consists of all of the variable bindings that are visible. This includes all of the bindings in the table for the innermost contour, and all of the bindings in the table for the contours it's nested inside, except those that are shadowed by inner bindings of the same names.