1.3.0 permalink Arrow_down_16x16



  • (macroexpand-all form)
Recursively performs all possible macroexpansions in form.

3 Examples top

  • user=> (use 'clojure.walk)
    user=> (macroexpand-all '(-> c (+ 3) (* 2)))
    (* (+ c 3) 2)
  • user=> (use 'clojure.walk)
    ; tryclj.com and lazybot on #clojure get the following wrong
    user=> (let [-> inc] (-> 5)) 
    ; Below macroexpansion is supposed to result in equivalent code to the above
    user=> (macroexpand-all '(let [-> inc] (-> 5)))
    (let* [-> inc] 5)
    user=> (let* [-> inc] 5)
    ; However, as is clear above, it does not
  • ;; differences between macroexpand-1, macroexpand and macroexpand-all 
    (require '[clojure.pprint :as pp]
             '[clojure.walk :as walk])
    (alter-var-root #'pp/*print-suppress-namespaces* (constantly true))
    (defmacro plus [n1 n2]
      `(+ ~n1 ~n2))
    (pp/pprint (macroexpand-1 '(plus 3 4)))   ;=> (+ 3 4)
    (pp/pprint (macroexpand   '(plus 3 4)))   ;=> (+ 3 4)
    (defmacro pl [p1 p2]
      `(plus ~p1 ~p2))
    (pp/pprint (macroexpand-1 '(pl 3 4)))     ;=> (plus 3 4)
    (pp/pprint (macroexpand   '(pl 3 4)))     ;=> (+ 3 4)
    (defmacro minus [m1 m2]
      `(- ~m1 ~m2))
    (defmacro calc [c1 c2]
      `(pl ~c1 (minus ~c1 ~c2)))
    (pp/pprint (macroexpand-1 '(calc 20 30)))
    ;=> (pl 20 (minus 20 30))
    (pp/pprint (macroexpand   '(calc 20 30)))
    ;=> (+ 20 (minus 20 30))
    (pp/pprint (walk/macroexpand-all '(calc 20 30)))
    ;=> (+ 20 (- 20 30))
Log in to add / edit an example.

See Also top

Log in to add a see also.

Plus_12x12 Minus_12x12 Source clojure/walk.clj:123 top

(defn macroexpand-all
  "Recursively performs all possible macroexpansions in form."
  {:added "1.1"}
  (prewalk (fn [x] (if (seq? x) (macroexpand x) x)) form))
Vars in clojure.walk/macroexpand-all:
Used in 0 other vars

Comments top

3 comment(s) for macroexpand-all.

DO NOT USE THIS FUNCTION, it doesn't handle special forms at all, and, as such, does not in fact expand into the ultimate macroexpansion of the form.

For example,

(require '[clojure.walk :as walk])
(println (walk/macroexpand-all '(quote (let [a 1] a))))

Will print

(quote (let* [a 1] a))

When the correct answer is

(quote (let [a 1] a))

Showing an utter unawareness of proper handling of special forms


@Sgeo - let is just a macro for let*:

(clojure.repl/source let) =>

(defmacro let
"binding => binding-form init-expr

 Evaluates the exprs in a lexical context in which the symbols in
 the binding-forms are bound to their respective init-exprs or parts
 {:added "1.0", :special-form true, :forms '[(let [bindings*] exprs*)]}
 [bindings & body]
 (assert-args let
     (vector? bindings) "a vector for its binding"
     (even? (count bindings)) "an even number of forms in binding vector")
  `(let* ~(destructure bindings) ~@body))

(quote (let [a 1] a)) is '(let [a 1] a) which evaluates to a list containing the symbol let, a vector [a 1], and a symbol a. In this context, the (let [a 1] a) is not code, but mere data, and as such, should not be macroexpanded at all, anymore than a string like "(-> a b c)" should be macroexpanded into "(c (b a))" (and yes, I know that's not the exact macroexpansion).

Log in to add a comment.