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.

4 Comments

  1. 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?

  2. Hans Nowak said,

    January 3, 2008 @ 10:55 pm

    I think so. I’m not all that familiar with Common Lisp.

  3. Anonymucus said,

    January 4, 2008 @ 12:56 am

    So somehow the report function isn’t a closure (except in the last example)? Why not?

  4. 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).

RSS feed for comments on this post