Browse Learn Clojure Foundations as a Java Developer

Use Quote and Unquote in Clojure Macros

Learn how quote, syntax quote, unquote, unquote-splicing, and auto-gensyms work together to build readable Clojure macro templates without variable capture.

Quoting controls what is treated as code and what is treated as data. In macro writing, this is the core skill: build a code template, then insert caller forms only where they belong.

For Java engineers, think of syntax quote as a safer source-template mechanism. It builds code, resolves many symbols, and lets you explicitly mark holes with unquote.

The Four Tools

Tool Meaning
'form Quote the form as data without evaluating it.
`form Syntax-quote the form, usually for macro templates.
~form Unquote one form inside syntax quote.
~@forms Splice a sequence of forms into the surrounding form.

Use regular quote when you want literal data. Use syntax quote when you are generating code.

Quote Treats Code as Data

1'(+ 1 2)
2;; => (+ 1 2)
3
4(+ 1 2)
5;; => 3

The first form is a list. The second form is a function call. Macros work because Clojure can represent source as ordinary data structures.

Syntax Quote Builds a Template

1`(println "hello")
2;; => (clojure.core/println "hello")

Syntax quote resolves println to clojure.core/println, which makes generated code less dependent on the caller’s local namespace.

Unquote Inserts a Caller Form

1(defmacro log-value
2  [label expr]
3  `(let [value# ~expr]
4     (println ~label value#)
5     value#))

~expr inserts the caller’s expression into the generated let. ~label inserts the label expression. value# becomes a generated local name.

Expansion makes the template visible:

1(macroexpand-1
2  '(log-value "total:" (+ 1 2)))
3
4;; roughly:
5(let [value__auto__ (+ 1 2)]
6  (clojure.core/println "total:" value__auto__)
7  value__auto__)

Unquote-Splicing Inserts Many Forms

Use ~@ when the caller passes a body of multiple forms:

1(defmacro do-with-message
2  [message & body]
3  `(do
4     (println ~message)
5     ~@body))

Without splicing, the body forms would be inserted as one list-like value rather than several forms in sequence.

Common Mistakes

Mistake Safer habit
Using regular quote for generated code Use syntax quote so core symbols resolve predictably.
Forgetting ~ The template contains a literal symbol instead of the caller form.
Using ~ where ~@ is needed Multiple body forms are inserted as one collection-like form.
Naming generated locals manually Use name# or gensym to avoid caller collisions.
Expanding only in your head Use macroexpand-1 at the REPL.

Review Checklist

Before shipping a macro template, ask:

Check Why it matters
Which parts are fixed template? Fixed code should be readable ordinary Clojure.
Which parts come from the caller? Caller forms should be inserted exactly where intended.
Are body forms spliced? Multiple forms need ~@ inside a surrounding do or similar form.
Are generated locals unique? Auto-gensyms prevent accidental variable capture.

Knowledge Check

### What does syntax quote usually do that regular quote does not? - [x] It builds a template and resolves many symbols to qualified names. - [ ] It immediately evaluates the form. - [ ] It converts Clojure code into Java source. - [ ] It disables macro expansion. > **Explanation:** Syntax quote is the usual macro template tool. It preserves a form as data while qualifying symbols such as `println`. ### When should you use `~@` instead of `~`? - [x] When inserting a sequence of body forms into generated code. - [ ] When inserting exactly one numeric value. - [ ] When quoting a literal list as data. - [ ] When defining a namespace. > **Explanation:** `~@` splices multiple forms into the surrounding syntax-quoted form. It is common for `& body` macro arguments. ### Why use `value#` in a syntax-quoted macro? - [x] To create a unique generated local and avoid variable capture. - [ ] To dereference an atom. - [ ] To mark the value as private. - [ ] To force the value to be a string. > **Explanation:** Auto-gensyms create generated symbols that should not collide with caller locals.
Revised on Saturday, May 23, 2026