Tuesday, May 4, 2010

Understanding Hygiene (part 1)

Because macroexpansion is performed before compilation, the compiler receives only core language expressions with known semantics (LAMBDA, DEFINE, SET, IF, ...).

What's important though is that the expressions received by the compiler contain a mixture of user- and macro-written code. For example, given the following hygienic OR macro:
(define-syntax or (form1 form2)
`(let ((tmp ,form1))
(if tmp
tmp
,form2)))
The code
(or foo bar)
is translated to:
(let ((tmp foo))
(if tmp
tmp
bar))
The blue parts are user-written, the white parts are macro-written.

The important thing is that parts with different colors do not interact.

So even if we use the variable name TMP, the code still works as expected because a white TMP doesn't interact with a blue TMP.
(or foo tmp)
is translated to:
(let ((tmp foo))
(if tmp
tmp
tmp))
Without the colors, the code would always return the value of FOO.

This is one part of the equation: the macro-written white TMP doesn't shadow the user-written blue TMP.

The other part is that user-written code mustn't shadow macro-written variables. If you have a (stupid) macro:
(define-syntax my-list (&rest args)
`(list ,@args))
and a user uses it thusly:
(let ((list 12))
(my-list 1 2 3))
This expands to:
(let ((list 12))
(list 1 2 3))
Again, this causes no problem, because different colors don't interact.

Everytime you create a piece of code with quasiquote, the system generates a new unique color.

3 comments:

Manuel Simoni said...

There's now a part 2.

Anonymous said...

"user-written code mustn't shadow macro-written variables"


If I understand correctly, the word
"mustn't" must be written from the
impementor's point of view, right?
For the programmer, it's "will not",
a guarantee, right?

Manuel Simoni said...

Correct.