Learn when to use macroexpand-1 for the next macro step and macroexpand for the fully expanded outer form, with review patterns for practical macro debugging.
macroexpand-1 and macroexpand are REPL tools for inspecting generated code. Use them before you debug a macro by trial and error.
The difference is scope:
| Tool | What it does | Best use |
|---|---|---|
macroexpand-1 |
Expands the outer macro call once. | Reviewing the macro you just wrote. |
macroexpand |
Repeatedly expands the outer form while it remains a macro call. | Seeing the larger shape after nested outer expansion. |
Neither tool evaluates the expanded code. They show code.
1(defmacro log-value
2 [label expr]
3 `(let [value# ~expr]
4 (println ~label value#)
5 value#))
Use macroexpand-1 to verify the immediate transformation:
1(macroexpand-1
2 '(log-value "total:" (+ 1 2)))
3
4;; roughly:
5(clojure.core/let [value__auto__ (+ 1 2)]
6 (clojure.core/println "total:" value__auto__)
7 value__auto__)
This is enough to answer the important review questions:
| Question | Expansion evidence |
|---|---|
Does (+ 1 2) run once? |
It appears once in the let binding. |
| Is the generated local safe? | The local has an auto-generated name. |
| Does the macro return the original value? | The generated form returns value__auto__. |
macroexpand keeps expanding the outermost form while it is a macro. It does not recursively walk every nested expression inside the result.
1(macroexpand
2 '(when false
3 (log-value "total:" (+ 1 2))))
4
5;; roughly:
6(if false
7 (do
8 (log-value "total:" (+ 1 2))))
The outer when expands. The nested log-value remains because it is no longer the outermost form being expanded by macroexpand.
If you need to inspect the nested call, expand that nested form directly:
1(macroexpand-1
2 '(log-value "total:" (+ 1 2)))
Expansion answers “what code will be generated?” Evaluation answers “what value does it produce?”
1(macroexpand-1 '(log-value "x" (+ 1 2)))
2;; returns a form
3
4(eval (macroexpand-1 '(log-value "x" (+ 1 2))))
5;; prints and returns 3, but eval is not normal macro debugging
In ordinary application work, avoid reaching for eval. Expand forms at the REPL, read them, then test the code that uses the macro.
| Step | Action |
|---|---|
| 1 | Write the desired call site first. |
| 2 | Run macroexpand-1 on a small representative call. |
| 3 | Check evaluation count, generated locals, and returned value. |
| 4 | Expand larger call shapes only after the small case is readable. |
| 5 | Add tests for behavior and, when useful, expansion shape. |
Expansion review is especially useful during Java-to-Clojure migration because it turns “macro magic” into generated Clojure that looks like the code you already know how to review.