Prev Up Next

Here is a definition of a rather more complicated
macro, `fluid-let` (sec 5.2).
`fluid-let` specifies temporary bindings for
a set of already existing lexical variables. Given a
`fluid-let` expression such as

(`fluid-let` ((**x** *9*) (**y** (**+** **y** *1*)))
(**+** **x** **y**))

we want the expansion to be

(`let` ((**OLD-X** **x**) (**OLD-Y** **y**))
(`set!` **x** *9*)
(`set!` **y** (**+** **y** *1*))
(`let` ((**RESULT** (`begin` (**+** **x** **y**))))
(`set!` **x** **OLD-X**)
(`set!` **y** **OLD-Y**)
**RESULT**))

where we want the identifiers **OLD-X**, **OLD-Y**,
and **RESULT** to be symbols that will not capture
variables in the expressions in the `fluid-let` form.

Here is how we go about fashioning a `fluid-let`
macro that implements what we want:

(`define-macro` `fluid-let`
(`lambda` (**xexe** . **body**)
(`let` ((**xx** (**map** **car** **xexe**))
(**ee** (**map** **cadr** **xexe**))
(**old-xx** (**map** (`lambda` (**ig**) (**gensym**)) **xexe**))
(**result** (**gensym**)))
`(`let` ,(**map** (`lambda` (**old-x** **x**) `(,**old-x** ,**x**))
**old-xx** **xx**)
,@(**map** (`lambda` (**x** **e**)
`(`set!` ,**x** ,**e**))
**xx** **ee**)
(`let` ((,**result** (`begin` ,@**body**)))
,@(**map** (`lambda` (**x** **old-x**)
`(`set!` ,**x** ,**old-x**))
**xx** **old-xx**)
,**result**)))))

The macro's arguments are:
**xexe**, the list of
variable/expression pairs introduced by the `fluid-let`; and
**body**, the list of
expressions in the body of the `fluid-let`. In our
example, these are ((**x** *9*) (**y** (**+** **y** *1*))) and `((`**+** **x**
**y**))

respectively.

The macro body introduces a bunch of local variables:
**xx** is the list of the variables extracted from the
variable/expression pairs.
**ee** is the corresponding list of
expressions. **old-xx** is a list of fresh identifiers,
one for each variable in **xx**. These are used to
store the *incoming* values of the **xx**, so we
can revert the **xx** back to them once the
`fluid-let` body has been evaluated.
**result** is another
fresh identifier, used to store the value of the
`fluid-let` body. In our example, **xx** is (**x** **y**)
and **ee** is (*9* (**+** **y** *1*)). Depending on how your
system implements **gensym**,
**old-xx** might be the
list (**GEN-63** **GEN-64**), and **result** might be **GEN-65**.

The output list is created by the macro for our given
example looks like

(`let` ((**GEN-63** **x**) (**GEN-64** **y**))
(`set!` **x** *9*)
(`set!` **y** (**+** **y** *1*))
(`let` ((**GEN-65** (`begin` (**+** **x** **y**))))
(`set!` **x** **GEN-63**)
(`set!` **y** **GEN-64**)
**GEN-65**))

which matches our requirement.

Prev Up Next