I've heard it said that Clojure's macro system is most similar to Common Lisp's macro system and that Racket (and Scheme) style macros are more powerful. Can anyone compare the differing approaches?
It is more similar to CL's macro system in that it doesn't force you to write hygienic macros -- though I think CL's macro system is actually more powerful than Scheme's since it does let you write unhygienic macros.
Clojure doesn't allow user defined _reader macros_, which means it is less flexible than either CL or Scheme. Basically, you can't really define your own syntax parser in Clojure, you are limited to what the Clojure reader can already parse. In CL and Scheme you don't have this restriction.
Scheme has historically been used as a research vehicle for macros. When the fifth revised specification of Scheme (known as R5RS) was written there were no consensus on the best practices for writing a system supporting unhygienic macros.
Since then both R6RS and R7RS has support for unhygienic macros.
Note that there are two important properties of the macro systems of modern Scheme implementations: hygiene and referential transparency. The second property is often overlooked.
The standard syntax-rules macro system of R5RS Scheme is hygienic
If a macro transformer inserts a binding for an identifier (variable or keyword),
the identifier will in effect be renamed throughout
its scope to avoid conflicts with other identifiers.
and referentially transparent
If a macro transformer inserts a free reference to
an identifier, the reference refers to the binding
that was visible where the transformer was specified,
regardless of any local bindings that may surround
the use of the macro.
The first property (automatically renaming of identifiers) is
prevents common errors. This property is easy to hack around in macro systems without automatic renaming. The macro writer simply generates a new identifier (gensym) each time a new identifier is needed.
The second one referential transparency is the killer feature. Names inserted by a macro refers to binding where the macro is defined. This means that the macro writer has control over the meaning of the binding of identifiers in the expansion. In other words: a user of a macro can not by accident rebind or assign values to identifiers inserted by a macro use.
When referential transparency is not supported, then one must be careful to load libraries in the right order:
Clojure doesn't allow user defined _reader macros_, which means it is less flexible than either CL or Scheme. Basically, you can't really define your own syntax parser in Clojure, you are limited to what the Clojure reader can already parse. In CL and Scheme you don't have this restriction.