💾 Archived View for idiomdrottning.org › guile-defmacro captured on 2023-07-22 at 16:54:21. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

A problem with Guile’s defmacro

All of this is well known to old Lisp nerds; move along, move along. And it might come across as gatekeepy or complicated to new folks. So I'm looking at you medium-experienced peeps for this one!

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

(define-macro
  (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:

(define-ir-syntax*
  (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.

define-ir-syntax