[plt-scheme] Re: Introducing bindings in a macro

From: David Van Horn (dvanhorn at cs.brandeis.edu)
Date: Thu Jan 17 11:05:31 EST 2008

Doug Williams wrote:
> I'd like to introduce bindings in a macro.  The commented code for 
> with-my-struct is more what I would like to see, but it doesn't work,  
> The uncommented code works, but is more complex and, well, uglier.  Is 
> there a clearer way (i.e. closer to the commented code) to write it? 

> ;  (define-syntax with-my-struct
> ;    (syntax-rules ()
> ;      ((with-my-struct s
> ;        expr ...)
> ;       (let ((a (my-struct-a s))
> ;             (b (my-struct-b s))
> ;             (c (my-struct-c s)))
> ;         expr ...))))

This is analogous to:

(define-syntax with-x
   (syntax-rules ()
     ((with-x e)
      (let ((x 'something))
        e))))

So (with-x x) --rewrites--> (let ((x 'something)) x) =eval=> 'something, 
or so you might think, but the x that was introduced and the x that was 
already apparent in the program are not the same x.  You could think of 
it as (with-x x) --rewrites--> (let ((x1 'something)) x) =eval=> unbound 
variable reference: x.

This is a consequence of hygiene.  In order to bend/break the hygienic 
invariant of expansion you need to resort to heavier machinery, ie. your 
working code.

In short, you can't (hygienically) introduce a binding in a macro that 
can be referenced by the program.  If you want a macro to bind an 
identifier that you can reference, you have to "give" the macro the 
identifier:

(define-syntax with-x
   (syntax-rules ()
     ((with-x x e)
      (let ((x 'something))
        e))))

Or:

(define-syntax with-my-struct
   (syntax-rules ()
     ((with-my-struct s (a b c) e0 e1 ...)
      (let ((a (my-struct-a s))
            (b (my-struct-b s))
            (c (my-struct-b s)))
        e0 e1 ...))))

David



Posted on the users mailing list.