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: fluid-let


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.