Page 1 of 1

What's wrong with my hygienic Lisp macros?

Posted: Sun Jan 25, 2009 7:32 pm
by Ali Clark
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.

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

Posted: Thu Jan 29, 2009 5:23 pm
by Ali Clark
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?