You are here:   ArielOrtiz.com > Programming Languages > Clojure Macros

[ Printer friendly page ]

The following notes are a subset of the Clojure macro and reader documentation, plus some examples.

Clojure Macros

Conventional Java Compilation

Java compilation diagram.

Clojure Compilation

Clojure compilation diagram.

Macro API

Function/Macro/Special Form Description
(defmacro name
  [params*]
  body)
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.
(macroexpand-1 form) If form represents a macro form, returns its expansion, else returns form.
(macroexpand-all form) Recursively performs all possible macroexpansions in form. You must import the namespace clojure.walk in order to use it.
`form

Syntax-quote. For all forms other than symbols, lists, vectors, sets and maps, `x is the same as 'x.

For symbols, syntax-quote resolves the symbol in the current context, yielding a fully-qualified symbol (i.e. namespace/name or fully.qualified.Classname). If a symbol is non-namespace-qualified and ends with "#", it is resolved to a generated symbol with the same name and a unique id suffix. For example, x# might resolve to x__66__auto__. All references to that symbol within a syntax-quoted expression resolve to the same generated symbol.

For lists/vectors/sets/maps, syntax-quote establishes a template of the corresponding data structure. Within a template, unqualified forms behave as if recursively syntax-quoted, but forms can be exempted from such recursive quoting by qualifying them with unquote and unquote-splicing (see below).

~form Unquote. Within a template, form will be treated as an expression to be replaced by its value.
~@form Unquote-splicing. Within a template, form will be treated as an expression (that must evaluate to a collection) to be replaced by its sequence of values.

Examples:

`(42 map f [1 2 3])   ⇒ (42 clojure.core/map user/f [1 2 3])

`(a b# c b#)          ⇒ (user/a b__46__auto__ user/c b__46__auto__)

`(1 2 (+ 1 2))        ⇒ (1 2 (clojure.core/+ 1 2))

`(1 2 ~(+ 1 2))       ⇒ (1 2 3)

`(1 2 (range 5))      ⇒ (1 2 (clojure.core/range 5))
 
`(1 2 ~(range 5))     ⇒ (1 2 (0 1 2 3 4))

`(1 2 ~@(range 5))    ⇒ (1 2 0 1 2 3 4)

;;; This macro defines a no-arg function called ‘name’. When the said
;;; function is called, it prints "Hello ‘name’!".
(defmacro make-hello-fun 
  [name] 
  `(defn ~name 
     [] 
     (printf "Hello %s!%n" (quote ~name))))
     
(macroexpand-1 '(make-hello-fun world)) 
⇒ (clojure.core/defn world 
    [] 
    (clojure.core/printf "Hello %s!%n" (quote world)))     
     
(make-hello-fun world)
(make-hello-fun dude)

(world)  ; Prints "Hello world!"
(dude)   ; Prints "Hello dude!"