Idiomdrottning’s homepage

A problem with Guile’s defmacro

Here is an anaphoric if defined in Guile’s defmacro:

  (aif-version-2 test then else)
  `(let ((it ,test))
     (if it ,then ,else)))

The problem with this is that let and if are also injected, not just it. (The syntax-case version on that page doesn’t have that problem.)

So if you’re running aif-version-2 in an environment where let or if is shadowed, you’re in trouble.

The entire selling point of the Scheme project was lexical scoping, after all (something Common Lisp also adopted just before the deadline kinda putting a wrench in the whole “common” idea as the big Lisps at the time struggled to implement lexical scoping).

In Common Lisp this shadow sensitivity doesn’t matter too much since they’re in a different name space anyway, although it’s not a surefire thing, so the traditional Common Lisp solution is to rename everything with gensyms.

In Chicken, they created a transformer that automatically does that, an “implicit renaming” macro transformer that implicitly renames everything you don’t “inject”. It’s a li’l bit wordy and verbose to use so I have define-ir-syntax* to make it simple to write macros:

  (aif-version-3 test then else)
  `(let ((,(inject it) ,test))
     (if it ,then ,else)))

It only injects it, everything else (in this case if and let) are renamed.