1.3.0 permalink Arrow_down_16x16

defmacro

clojure.core

  • (defmacro name doc-string? attr-map? [params*] body)
  • (defmacro 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.

3 Examples top

  • (defmacro with-tree [tree & body]
      "works on a JTree and restores its expanded paths after executing body"
      `(let [tree# ~tree
             root# (.getRoot (.getModel tree#))
             expanded# (if-let [x# (.getExpandedDescendants
                                    tree# (TreePath. root#))]
                         (enumeration-seq x#)
                         ())
             selectionpaths# (. selectionmodel# getSelectionPaths)]
         ~@body
         (doseq [path# expanded#]
           (.expandPath tree# path#))))
    
    ;; usage:
    
    (with-tree *one-jtree-instance*
       ;; some code here...
      )
  • (defmacro unless [pred a b]
      `(if (not ~pred) ~a ~b))
    
    ;; usage:
    
    (unless false (println "Will print") (println "Will not print"))
  • (def dbg 1)
    
    (defmacro chk-flagM
      "Throws an exception if flag does not resolve; else returns flag's value."
      [flag]
      (if (not (resolve flag))
        (throw (Exception. (str 'flag " is not a valid var.")))
        flag))
    
    (defn write-csv-file
      "Writes a csv file using a key and an s-o-s"
      [out-sos out-file]
    
      (if (>= (chk-flagM dbg) 2)
        (println (first out-sos), "\n", out-file))
    
      (spit out-file "" :append false)
      (with-open [out-data (io/writer out-file)]
          (csv/write-csv out-data (map #(concat % [""]) out-sos))))
    
    
Log in to add / edit an example.

See Also top

Log in to add a see also.

Plus_12x12 Minus_12x12 Source clojure/core.clj:405 top

(def

 ^{:doc "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."
   :arglists '([name doc-string? attr-map? [params*] body]
                 [name doc-string? attr-map? ([params*] body)+ attr-map?])
   :added "1.0"}
 defmacro (fn [&form &env 
                name & args]
             (let [prefix (loop [p (list name) args args]
                            (let [f (first args)]
                              (if (string? f)
                                (recur (cons f p) (next args))
                                (if (map? f)
                                  (recur (cons f p) (next args))
                                  p))))
                   fdecl (loop [fd args]
                           (if (string? (first fd))
                             (recur (next fd))
                             (if (map? (first fd))
                               (recur (next fd))
                               fd)))
                   fdecl (if (vector? (first fdecl))
                           (list fdecl)
                           fdecl)
                   add-implicit-args (fn [fd]
                             (let [args (first fd)]
                               (cons (vec (cons '&form (cons '&env args))) (next fd))))
                   add-args (fn [acc ds]
                              (if (nil? ds)
                                acc
                                (let [d (first ds)]
                                  (if (map? d)
                                    (conj acc d)
                                    (recur (conj acc (add-implicit-args d)) (next ds))))))
                   fdecl (seq (add-args [] fdecl))
                   decl (loop [p prefix d fdecl]
                          (if p
                            (recur (next p) (cons (first p) d))
                            d))]
               (list 'do
                     (cons `defn decl)
                     (list '. (list 'var name) '(setMacro))
                     (list 'var name)))))
Vars in clojure.core/defmacro:
Used in 0 other vars

Comments top

3 comment(s) for defmacro.

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

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__)

@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.

Log in to add a comment.