[racket] Again on bindings visibility in eval

From: Mark Engelberg (mark.engelberg at gmail.com)
Date: Fri Jul 15 14:34:25 EDT 2011

OK, so here are the main points I'm gathering from this discussion.

1.  Clojure's quasiquote system does some extra things behind the
scenes in terms of generating temporary variables and qualifying
variable names with their namespace in such a way that the macros you
write are reasonably hygienic.
2.  They are not perfectly hygienic because the gensym is simplistic
and there may be ways to defeat it if someone tried hard enough.
Also, rebinding the global things that the macro depends on may result
in unintended behavior.  (Then again, you could argue that if you
rebind the global "if", you really do want macros like "while" to
3.  Clojure does not have macros that are only valid within some local
context.  All macros are global, and this might result in a lack of
expressiveness versus Racket's system.
4.  Racket's macro system tracks things like source code location (and
possibly other things?) useful for debugging.

Point 3 is the main one I'm still getting my head around.  I had to do
a little research to understand what everyone was talking about here
with "local macros" and "scoped macros".  I see now that in Racket, if
you define a macro inside some sort of function body (or other lexical
scope), it is only valid within that scope.

Here are a couple of examples from Clojure to contrast that behavior with:
(def x 3)

(let [x 2]
  (defmacro apply-to-x [y]
    `(~y ~x)))

In this code snippet, x is a global, and apply-to-x is a global macro,
but the macro does look up x in its local context, i.e., (apply-to-x
identity) yields 2, not 3.

On the other hand removing the ~ from the x like this:
(let [x 2]
  (defmacro apply-to-x [y]
    `(~y x)))
causes the x in the macro to refer to the global x.  So, (apply-to-x
identity) yields 3.

So it is possible in Clojure to make the macro refer to its local
scope, but the macro itself is always global.

I recognize that this means there are things you can do in Racket with
macros that would be extremely difficult or impossible in Clojure, but
I don't have a good sense for how often this would occur in practice.
I gather it would be more of an issue for things on a large scale like
Racket's class system.

Posted on the users mailing list.