On Fri, Jun 26, 2009 at 3:53 AM, Michele Simionato<michele.simion...@gmail.com> wrote: > > I am writing a rather long series of articles about Scheme on Artima, > "The Adventures of a Pythonista in Schemeland" (maybe somebody here > has > heard of it). Last week I arrived at point of discussing hygienic > macros > (http://www.artima.com/weblogs/viewpost.jsp?thread=260195) > and I wanted to spent a few words about the differences between > Scheme and other lisps. In particular I want to asset the status of > Clojure > macros with respect to hygiene. > > Since they look a lot like Common Lisp macros, I initially assumed > that > Clojure macros were not hygienic, but after performing some experiment > I > realized that I was half wrong. For instance, I expected this code to > fail due to free-symbol capture: > > user=> (defmacro m [x] `(list ~x)) > #'user/m > user=> (let [list 1] (m 2)) > (2) > > Instead, it works correctly. Therefore, I assume that Clojure > is renaming the free symbols in the macro body (in this case 'list). > On the other hand, Clojure macros are not fully hygienic, otherwise > a would not be defined in this example: > > user=> (defmacro def-a[x] `(def a ~x)) > #'user/def-a > user=> (def-a 1) > #'user/a > user=> a > 1 > > It seems that in order to avoid variable capture for bound symbols > I need to use good old (gensym): > > user=> (defmacro def-a[x] (let [a (gensym)] `(def ~a ~x))) > #'user/def-a > user=> (def-a 1) > #'user/G__77 > > Am I right in my assumptions?
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 --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---