What's wrong with my hygienic Lisp macros?

Discussion of Scheme and Racket
Post Reply
Ali Clark
Posts: 15
Joined: Mon Aug 25, 2008 10:23 am

What's wrong with my hygienic Lisp macros?

Post by Ali Clark » Sun Jan 25, 2009 7:32 pm

Hi there,

I started learning Scheme after I'd learned a bit about Common Lisp. I found the Scheme hygienic macros difficult to do more advanced stuff like write macros that write macros and partly because of the system getting confused by different levels of pattern matching. It got ugly. So now I just use a Scheme's define-macro if I want a macro. But I know this is probably not a desirable way to roll with the hygiene problem. So I wrote a little system to help my Lisp macros be hygienic.

The idea is thus (untested code):

Code: Select all

(define my-list list)            ; No-one will ever think about calling their variables "my-list"

(define-macro (my-foo x)
  `(my-list ,@x))                ; Sneakily use "my-list" when really we mean "list"

(define (my-bar list)            ; The end-user expects referential transparency
  (my-foo (1 2 list 3 4)))       ; Since my-foo expands to (my-list 1 2 list 3) and not (list 1 2 list 3), we are okay.

(my-bar '(1 2 3 4))              ; This works as intended.
This doesn't do anything useful, but the user redefined the variable "list" in my-bar and it still worked because we were using a different pointer to the list (in this case, my-list).
Now go through that and replace my-list with a gensym and use a hash table of 'list -> 'g01 to keep track of the gensym whenever we really mean "list".

So what's wrong with this system? Its seems pretty obvious, so I'd be surprised if no-one has tried it before.
I'm currently using this (implemented ~100 loc) for my own Scheme code and would like to be persuaded why not to use it.

Ali Clark
Posts: 15
Joined: Mon Aug 25, 2008 10:23 am

Re: What's wrong with my hygienic Lisp macros?

Post by Ali Clark » Thu Jan 29, 2009 5:23 pm

Still no comment? Well anyway I thought it might be a good idea to show the actual code that would be used...

Code: Select all

(add-hygienic! list)            ; Makes a new gensym, g0, and adds an entry for 'list -> 'g0 in a hash table, then expands to (define g0 list)

(define-macro (my-foo x)
  `(,(hs 'list) ,@x))           ; Retrieve the appropriate gensym from the hash table

(define (my-bar list)
  (my-foo (1 2 list 3 4)))

(my-bar '(1 2 3 4))
The above code expands to:

Code: Select all

(define g0 list)

(define (my-bar list)
  (g0 1 2 list 3 4))

(my-bar '(1 2 3 4))
Where g0 is the same gensymed symbol throughout.

So anyway, like I said, I'd really like a brief explanation or link to why I shouldn't use this method of hygiene, and if not, why aren't other people already using this, or are they?

Post Reply