[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

macroexpansion environments

Here's an interesting problem with Common Lisp:

(defvar x 1)
(defmacro m ()
  (print x)
  `(list ,x x))
(let ((x 2)) (m))     ;case A
(let ((x 2)) () (m))  ;case B

In case A it will print a 1 and return the list (1 2).
In case B it will print a 2 and return the list (2 2).

The problem is that special forms such as LET have to expand at least the
first form of the body in order to find out if it returns a declaration.
(More may have to be expanded if it does expand into a declaration.)
The question is what environment does the macro call get expanded in.
You'd expect that they'd have to be expanded inside the bindings set up
by the LET itself, but this isn't possible if the macro returns a
declaration, which might affect the binding. In the example above, all
instances of X are special, but that needn't have been the case. What's
disconcerting is that the results are different for the seemingly
identical cases.

Now since one isn't supposed to depend on when macros get evaluated,
nor how often they get evaluated, it might be possible ignore the
problem of having different side effects, and one could implement
the special forms to re-expand the macro if it didn't expand into a
declaration and the environment has changed. That might "resolve"
the issues for the example above, but I'm still concerned.
For example:

(setq y 1)
(defmacro decl () `(declare (special y)))
(defmacro m () (print y) `(list ,y y)))
(let ((y 2)) (decl) (m))

I don't think it would be reasonable to disallow macros expanding into
declarations. Ideas?