This is the mail archive of the guile@cygnus.com mailing list for the guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Changing the environment


Jost Boekemeier <jostobfe@calvados.zrz.TU-Berlin.DE> writes:

> is it possible to get and change the environment of a given closure?

In general, no.

It might be possible by changing the module that a closure belongs to,
and thereby affecting its top-level bindings, but I do not recommend
that in any case.

> The function 
> 
> (define f (lambda (arg) (display arg) (display x) (display y) )
> 
> has an environment, which is an obarray with one entry: "arg".

More precisely, the environment includes *all* bindings that are
lexically visible at the point of the lambda.  This includes all
bindings made outside the lambde, including all top-level bindings
("f", for example).  It does *not* include "arg", which is a free
variable inside the lambda.  Each time you invoke f, a new binding for
"arg" is made, and a new environment is constructed by extending the
environment of "f" with this new binding.

Now, there must also exist bindings for "x" and "y" in the environment
for f (everything else would lead to an error).  Say they are at the
top-level:

    (define x #f)
    (define y #f)
    (define f (lambda (arg) (display arg) (display x) (display y)))

In Scheme, you can't change the environment of a closure, so "x" and
"y" in the body of f will always refer to the bindings introduced by
the two defines for "x" and "y".  You can only change the *values*
that these bindings have while calling f.  You want to do this only
temporarily, so that "x" and "y" revert to their old values after f
has returned.  This is what `fluid-let' is intended to do.  So

    (define b
      (lambda (arg)
	(fluid-let ((x 1)
                    (y 2))
          (f arg))))

This expands into something like

    (define b
      (lambda (arg)
        (let ((old-x 1)
              (old-y 2))
          (let ((swapper (lambda () (swap x old-x) (swap y old-y))))
            (dynamic-wind
              swapper
              (lambda () (f arg))
              swapper)))))

with

    (define-macro (swap a b)
      (let ((t (gensym)))
        `(let ((,t ,a))
           (set! ,a ,b)
           (set! ,b ,t))))

See the other thread about `fluid-let'.