fluid-let
After comparing function argument lists in Python and Scheme, here’s a Scheme construct that Python definitely doesn’t have. (Although I’m not saying that it would be impossible to implement something similar…)
The construct I’m talking about is a special form called fluid-let. It’s not part of the Scheme standard, but many implementations provide it anyway (including Chicken).
Consider the following code:
(define x 4)
(define (report)
(printf "I ate ~a hamburgers.~n" x))
(report)
This prints “I ate 4 hamburgers.” So far, so good.
Now, if we wrap the call to report in a let…
(let ((x 15))
(report))
…it *still* prints “I ate 4 hamburgers.” This is expected, because the x defined in the let does not affect the x referenced by report, which is a global.
However, with fluid-let we can change this, and shadow the global x anyway. Witness:
(fluid-let ((x 15))
(report))
This prints “I ate 15 hamburgers.” This greatly mystified me at first, but it’s actually not so difficult to understand what is going on. fluid-let stores the old value of x, then sets it to the new value (15), then executes the code in its body, and finally restores x to its original value.
In fact, fluid-let can be written as a macro. Quite instructive, although not necessarily easy to understand…
Note: Apparently fluid-let only works with globals. The following does *not* work (at least not in Chicken):
(define (make-report x)
(lambda ()
(printf "I ate ~a hamburgers.~n" x)))
(define report (make-report 4))
(report) ;; 4 hamburgers
;; error:
(fluid-let ((x 15))
(report))
…because there is no global x to shadow.
Matt Moriarity said,
January 3, 2008 @ 9:18 pm
this is the same as a regular let in common lisp with a special variable, correct? CL uses dynamic scoping to achieve this. Since scheme uses lexical scoping only, it needs a different form to achieve this, right?
Hans Nowak said,
January 3, 2008 @ 10:55 pm
I think so. I’m not all that familiar with Common Lisp.
Anonymucus said,
January 4, 2008 @ 12:56 am
So somehow the report function isn’t a closure (except in the last example)? Why not?
Max said,
January 7, 2008 @ 7:54 am
report is a closure, but Scheme closures doesn’t close over global variables (as far as I understand — I’ve never used Scheme beyond GIMP scripts).