I mostly agree with absz, but in thinking deeply about lisp-likes and their implementation, I've stumbled on the formal equivalency of dynamic scoping on the expression-side to lexical scoping on the program-logic-side. Try taking a look at 'ac in ac.scm - it has an 'env parameter which is formally equivalent to a dynamic scoping rule for lexical compilation.
Basically, suppose we have the following code:
(fn (x)
(fn (y)
(fn (x) x)))
Now suppose that our macro/code-walker starts at the topmost branch, with an empty dynamic environment, '()
It then enters the first fn and creates a dynamic entry:
Oh, I agree, dynamic scoping and lexical scoping are formally equivalent. For one thing, basic computer architectures are all dynamically scoped, with 2^32 (or whatever) variables, one at each memory address. Also, as you say, you can just pick one dynamic variable and use it to hold the lexical environment as you walk through a program. (Unfortunately, I don't know enough to see what the really cool implications of this are, but I'm sure it has some.)
My question is, why is lexical scoping considered better for functions, but dynamic scoping for macros? And more specifically, are these actually cases where different solutions are better, or is it an artifact of the fact that we don't know how to implement lexically scoped macros very well?
Yes: a code-walker interpreter with dynamic lookup can implement lexical scope, provided you don't pass functions around (on the interpreted-language side).
If you do pass functions around though, you need to keep separate slightly-different versions of the environment variable, and attach those to the functions you pass around on the interpreted-language side.