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.