Skip to content

clojure.core/defmacro

View this page on ClojureDocs

Type: macro Added: Clojure 1.0 Examples: 5 Runnable: 2
([name doc-string? attr-map? [params*] body] [name doc-string? attr-map? ([params*] body) + attr-map?])

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

by Kototama on . May have evaluation errors.
by Clinton on
by octopusgrabbus on
by vale981 on . May have evaluation errors.
by jimka2001 on . May have evaluation errors.

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-all
doesn'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.