Welcome! Please see the About page for a little more info on how this works.

0 votes
in Macros by
(defmacro test [expr]
  (letfn [(helper [expr]
            (println expr)
            (rest expr))]
    (func expr)
    (helper expr)))

(defn func [x]
 (println x))

(macroexpand '(test (+ 1 2)))

;;the evaluator prints:
;;(+ 1 2)
;;(+ 1 2)
;;(1 2)

It is very counterintuitive as both the internal defined function (helper) and external (func) behave similarly by not evaluating (+ 1 2). There was an answer to this on stackoverflow.com (https://stackoverflow.com/questions/54394977/evaluation-of-arguments-in-function-called-by-macro), but it was not good enough.

1 Answer

+3 votes
selected by
Best answer

Both the internal and external function are behaving the same - they receive a list.

The evaluation happens prior to invocation (so it's not "the function" that is doing the evaluation but the call site invoking it).

Here, the argument to func and helper is the symbol expr. Symbols are evaluated by resolving that "name" to a value in the current lexical context, here defined in the defmacro parameters. It resolves to a list (+ 1 2). That list is passed to the function. Evaluating that list would require evaluating the argument twice!

Macro expansion is not evaluation and the arguments are not evaluated.

Thank you very much!