clojure.core/defmacro¶
Like defn, but the resulting function name is declared as a macro and will be used as a macro by the compiler when it is called.
Examples¶
Note by steveminer¶
The body of a macro has two implicitly bound symbols: &form and &env. They work like two extra unnamed args. The names begin with '&' to avoid name clashes with normal user-defined symbols. The value of &form is the form of the original macro call before macro expansion. There's useful meta-data on &form. The value of &env is the "environment", which is basically a map of lexical bindings. The keys of &env are the lexically bound symbols. The values are internal compiler details, and probably aren't useful for user code.
See also: http://blog.jayfields.com/2011/02/clojure-and.html
Note by Arlen¶
Due to syntax-quote resolving symbols (see the Clojure reader docs), you won't be able to include a regular let statement inside a macro, i.e.:
(defmacro m [] `(let [x 1] x)) (m) ; => CompilerException java.lang.RuntimeException: Can't let qualified name: user/x, compiling:(NO_SOURCE_PATH:1)
We can see why:
(macroexpand-1 '(m)) ; => (clojure.core/let [user/x 1] user/x)
The syntax-quote has resolved x to user/x—which can't be let. This is a good thing, as it's signalling to us that we should use gensyms by appending #:
(defmacro m [] `(let [x# 1] x#)) (m) ; => 1 (macroexpand-1 '(m)) ; => (clojure.core/let [x__383__auto__ 1] x__383__auto__)
Note by travis_rodman¶
@Arlen: If you want to capture the local variables, or create a non-locally scoped variable, you can prepend them with ~', allow a namespace capture:
(defmacro m [] `(let [~'x 1] ~'x)) (m) ; => 1 (macroexpand-1 '(m)) ; => (clojure.core/let [x 1] x)
useful, if you desire it.
Note by peter-kehl¶
When debugging macros that use &env, beware that
clojure.walk/macroexpand-alldoesn't "set up" any symbols. It ignores any symbols from
(let [...] ...)and similar. To test &env, run the macro directly.
Note by Antigen-1¶
(defn foldl
[p i ss]
(if (andmap seq ss)
;; `recur` is not a procedure
(recur p (p i (map first ss)) (map rest ss))
i))
(defn andmap [p s] (reduce #(and %1 (p %2)) true s))
(defn seq-of-len?
[l t n]
(and (t l) (= n (count l))))
(defmacro for-fold
"A macro like for/fold in Racket"
[[& accs] [& itrs] & body]
(doseq
[cl (into `~accs `~itrs)]
(assert (and (seq-of-len? cl list? 2) (symbol? (first cl))) (str "Invalid accumulator or iterator:" cl)))
(let [acc-ids (map first `~accs)
inits (map second `~accs)
itr-ids (map first `~itrs)
seqs (map second `~itrs)
sym `result#
len (count `~accs)
all (into acc-ids itr-ids)]
(assert (= (count all) (count (set all)))
"Duplicate names")
`(foldl (fn [[~@acc-ids] [~@itr-ids]]
(let [~sym (let [] ~@body)]
(assert (seq-of-len? ~sym vector? ~len) (str "Invalid result:" ~sym))
~sym))
[~@inits]
[~@seqs])))
See also¶
Content from the matching ClojureDocs page, with authors credited on each contribution.