This is a common problem with dynamically-scoped values in many languages (not just Racket). Here's what happens when you evaluate the code:
- The
location
parameter is defined with value"here"
- Enter the
let
... - Enter
parameterize
... - The parameter
location
is dynamically updated with the value"with a fox"
- The
lambda
expression is evaluated to create a closure which closes overlocation
- Return from
parameterized
block—parameterlocation
reverts to its original value of"here"
- The resulting
lambda
is bound toget
- Evaluate
let
body... - You call
(get)
, and it looks up the current value oflocation
, which is"here"
, and that's the result.
If you carefully read the documentation on parameters it explains that the parameter always takes the value of the closest update in the stack. Since your update with the value "with a fox"
gets popped off the stack before going into the let
body, it's no longer visible when you make the actual call to get
. A simple fix is to copy the value from the parameter and let the closure close over the copy:
(define location (make-parameter "here"))
(let ([get (parameterize ([location "with a fox"])
(let ([loc (location)])
(lambda () loc)))])
(get))
Now the lambda
closes over loc
, which should have the expected value.