The following Scheme code
(let ((x 1))
(define (f y) (+ x y))
(set! x 2)
(f 3) )
which evaluates to 5 instead of 4. It is surprising considering Scheme promotes static scoping. Allowing subsequent mutation to affect bindings in the closed environment in a closure seems to revert to kinda dynamic scoping. Any specific reason that it is allowed?
EDIT:
I realized the code above is less obvious to reveal the problem I am concerned. I put another code fragment below:
(define x 1)
(define (f y) (+ x y))
(set! x 2)
(f 3) ; evaluates to 5 instead of 4
Allowing such mutation is excellent. It allows you to define objects with internal state, accessible only through pre-arranged means:
There is no way to change that
xexcept through theffunction and its established protocols – precisely because of lexical scoping in Scheme.The
xvariable refers to a memory cell in the internal environment frame belonging to thatletin which the internallambdais defined – thus returning the combination oflambdaand its defining environment, otherwise known as “closure”.And if you do not provide the protocols for mutating this internal variable, nothing can change it, as it is internal and we’ve long left the defining scope:
EDIT: your new code, which changes the meaning of your question completely, there’s no problem there as well. It is like we are still inside that defining environment, so naturally the internal variable is still accessible.
More problematic is the following
I would expect the second define to not interfere with the first, but R5RS says
defineis likeset!in the top-level.Closures package their defining environments with them. Top-level environment is always accessible.
The variable
xthatfrefers to, lives in the top-level environment, and hence is accessible from any code in the same scope. That is to say, any code.