This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

What's wrong with my hygienic Lisp macros?

2 posts · 4418 views

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):
(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?

Still no comment? Well anyway I thought it might be a good idea to show the actual code that would be used...
(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:
(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?