Not quite. But it takes a bit more digging to see how. Most important,
the macro does not yield an expansion with an unqualified 'a:
user=> (ns foo)
nil
foo=> (defmacro def-a[x] `(def a ~x))
#'foo/def-a
;use macroexpand to see what the macro does
foo=> (macroexpand-1 '(def-a 42))
(def foo/a 42)
Therefor, its use is still hygienic - in the expansion, 'a means
whatever it means in ns foo:
foo=> (in-ns 'user)
#<Namespace user>
;currently defining vars can't be done from a foreign namespace, so
this fails as expected
user=> (foo/def-a 42)
java.lang.Exception: Can't refer to qualified var that doesn't exist
(NO_SOURCE_FILE:9)
user=> (in-ns 'foo)
#<Namespace foo>
foo=> a
java.lang.Exception: Unable to resolve symbol: a in this context
(NO_SOURCE_FILE:0)
foo=> (def-a 42)
#'foo/a
foo=> a
42
> Is there a document explaining how
> Clojure macros work? The macro system seems quite unique, in the sense
> that I do not know of any other macro system working in the same way.
>
It is unique, and it is not renaming. I call the process resolving,
and the basic purpose is hygiene - macros yield qualified symbols
reflecting their meanings at macro definition time.
http://clojure.org/reader#syntax-quote
http://clojure.org/evaluation
You can use auto-gensyms (bar#) to get unique names, but you must take
extra effort to get a macro to emit an unqualified (and thus
capturing) symbol, e.g. ~'bar will yield the unqualified symbol 'bar
in the expansion.
Hope that helps (tip - use macroexpand while exploring macros)
Rich
How not?
> Also, it looks like
> Clojure macros are runtime macros,
> i.e. they may depend from runtime values and macro expansion cannot be
> performed statically
> without running the program (which is usually considered pretty bad).
> Am I correct?
No. Please use macroexpand in order to facilitate yourunderstanding.
By using quote, and not syntax-quote, you have written an
intentionally capturing macro:
user=> (def x 42)
#'user/x
user=> (defmacro m[] 'x)
#'user/m
user=> (macroexpand '(m))
x
user=> (let [x 43] (m)) ;i.e. (let [x 43] x)
43
The correct way is to use syntax-quote:
user=> (defmacro m[] `x)
#'user/m
user=> (macroexpand '(m))
user/x
user=> (let [x 43] (m)) ;i.e. (let [x 43] user/x)
42
> Finally, as an unrelated question, is there an equivalent of macrolet
> in Clojure?
Not yet.
Rich
Am 26.06.2009 um 16:39 schrieb Michele Simionato:
> That means that I do not need gensym, I can just add a `#` to the
> identifiers I want to introduce hygienically, right?
> I guess this is what you meant by autogensym in the other post. A
> pretty cool idea, actually.
Exactly, here a short real-world example.
(defmacro with-out-str
[& body]
`(let [out-string# (StringWriter.)]
(binding [*out* out-string#]
~@body)
(.toString out-string#)))
This macro is 100% hygienic. Things like
binding or StringWriter are resolved to the
binding and StringWriter in effect, when the
macro was defined. Also out-string# generates
a new local which does not clash with the
user code injected via ~@body.
I think this is a very easy way to write macros.
It is almost a visual template of the final code.
Note: I didn't investigate whether there is
a StringWriter and what it's interface is. The
point of the example is the macro...
Sincerely
Meikel
> Finally, as an unrelated question, is there an equivalent of macrolet
> in Clojure?
Not in Clojure itself, but there is an implementation in an external
library, clojure.contrib.macro-utils:
http://github.com/richhickey/clojure-contrib/blob/
82cf0409d0fcb71be477ebfc4da18ee2128a2ad1/src/clojure/contrib/
macro_utils.clj
Concerning your other questions, I think most of them have been
answered already. In general, the main difference between macros in
Clojure and Common Lisp comes from the fact that Clojure has
namespaces and both namespace-qualified and unqualified symbols. This
takes care of many of the typical problems with non-hygienic macros
in Common Lisp, while still permitting intentional variable capture.
It's a pretty neat design once you have understood all the details!
Konrad.