Re: fluid-let

Russ McManus (mcmanr@eq.gs.com)
17 Aug 1998 16:43:07 -0400

Marius Vollmer <mvo@zagadka.ping.de> writes:

> Russ McManus <mcmanr@eq.gs.com> writes:
>
> > Is this closer?
>
> Yep. You might want to look at fluidlet.scm from SLIB and see how
> they do it with syntax-rules macros. You might also note (as I have
> just this moment) that `fluid-let' from SLIB does not save the
> external values on reentry, which I find strange. What do you say, is
> it a bug in SLIB?

Well, if you were right before, and you're right about the slib code,
then slib indeed has a bug in it. (Hmmm. That wasn't very helpful).

Actually I purposefully avoided looking at anyone else's code, so that
I could get some practice writing a non-trivial macro. Obviously,
once you know the concepts, it makes sense to learn from others' code.

> > (defmacro fluid-let (binding-ls . body)
> > (let* ((expanded-binding-ls
> > (map (lambda (binding)
> > (append binding (list (gensym))))
>
> You might want to put the gensym first, with (cons (gensym) binding).

This was actually a conscious choice. In my (perhaps twisted) mind,
the variable name is the 'car' of a binding, and it's value is the
'cadr', so I didn't want to confuse myself.

> > binding-ls))
> > (tmp-var (gensym))
> > (environment-ls
> > (map (lambda (binding)
> > `(,(caddr binding) ,(cadr binding)))
> > expanded-binding-ls))
> > (swap-ls
> > (map (lambda (binding)
> > `(begin
> > (set! ,tmp-var ,(car binding))
> > (set! ,(car binding) ,(caddr binding))
> > (set! ,(caddr binding) ,tmp-var)))
>
> Binding temp-var with `let' might be cleaner here.

Since I was using 'set!' willy-nilly, I just kept going. See below
for version with 'let'.

> `(let ((,tmp-var ,(car binding)))
> (set! ,(car binding) ,(caddr binding))
> (set! ,(caddr binding) ,tmp-var))
>
> > expanded-binding-ls)))
> > `(let ,environment-ls
> > (let ((,tmp-var #f))
> > (dynamic-wind
> > (lambda () ,@swap-ls)
> > (lambda () ,@body)
> > (lambda () ,@swap-ls))))))
>
> I think there is no need to duplicate the (lambda () ,@swap-ls), just
> make one closure outside of the dynamic-wind.

Wow. You rule.

> > Now on to with-fluids...
>
> And after that you might want to try to express fluid-let with
> defmacro but *without* gensym, while still being referential
> transparent.

<ignorance>
Why is it important to get rid of gensym? Where can I find an
understandable definition of 'referential transparency'?
</ignorance>

Take three on fluid-let, with all your suggestions (I hope I didn't
bungle this one):

(defmacro fluid-let (binding-ls . body)
(let* ((expanded-binding-ls (map (lambda (binding)
(append binding (list (gensym))))
binding-ls))
(tmp-var (gensym))
(environment-ls (map (lambda (binding)
`(,(caddr binding) ,(cadr binding)))
expanded-binding-ls))
(swap-form `(lambda ()
,@(map (lambda (binding)
`(let ((,tmp-var ,(car binding)))
(set! ,(car binding) ,(caddr binding))
(set! ,(caddr binding) ,tmp-var)))
expanded-binding-ls)))
(swap (gensym)))
`(let ,environment-ls
(let ((,swap ,swap-form))
(dynamic-wind ,swap (lambda () ,@body) ,swap)))))

It seems to be getting shorter. I guess that's Scheme for 'ya.

-russ

--

mainstream, adj. fanatically opposed to anything at all unusual.