Don Tomato
Don Tomato

Reputation: 3519

How to pass list of args to variadic macro

I have a macro (I've simplified everything a lot):

(defmacro m1 [error & messages]
  `(if ~error
     (str "Error: " ~@messages)
     (str ~@messages)))

It works pretty well. But now I want to reuse it in a function with args [& messages]:

If I define this function the following way:

(defn error [& messages]
  (m1 true messages))

It works, but incorrectly of course. If I call (error "msg") it returns "Error: (\"msg\")"

But if I do something like:

(defn error [& messages]
  (apply m1 true messages))

It causes an error

; Syntax error compiling at .... ; Can't take value of a macro

So the question is how to pass messages list to variadic macro?

Upvotes: 0

Views: 49

Answers (2)

Denis Fuenzalida
Denis Fuenzalida

Reputation: 3346

Maybe it's not what you are looking for but one option is to provide multiple arities to your function instead of using apply:

(defmacro m1 [error & messages]
  `(if ~error
     (str "Error: " ~@messages)
     (str ~@messages)))

(defn error
  ([b & messages] (m1 b messages))
  ([messages] (m1 true messages)))

Upvotes: 0

Eugene Pakhomov
Eugene Pakhomov

Reputation: 10652

You cannot. Macros operate at macro expansion time, and there, messages is just a symbol.

m1 doesn't need to be a macro at all - it can be a plain function. And whenever you can use a function instead of a macro, you should most definitely do so to avoid any similar issues.

Upvotes: 3

Related Questions