Reputation: 1111
I am trying to define a macro like this:
(defmacro foo-macro
"[name] is the name of the function to define
[meta-data] is the map that defines the meta-data of the function"
[name meta-data]
(let [vals (gensym "label-")]
`(def ~name
^@~meta-data
(fn [~vals] (eval nil)))))
However, I am getting this compilation error:
Unhandled java.lang.IllegalArgumentException Metadata must be Symbol,Keyword,String or Map
I think this is normal. However, I am not sure how I can make such a macro to work, or if it is even possible.
Note: I do not want to use with-meta
. Read the revision of the resolution of this other question to understand why: Clojure: issues getting the symbol of a function in a looping context.
The only reason why I would use with-meta
, is if you have a way to make it return a non-AFunc identifier.
Upvotes: 0
Views: 283
Reputation: 3212
I'm sorry, but you do want to use with-meta
, you just want to use it within your macro rather than within the code you return.
The form that you get by reading ^{:foo :bar} (fn [])
is approximately the same as what you get by evaluating (with-meta `(fn []))
, so that's what you want to do in your macro: evaluate the with-meta
call while generating code.
(defmacro foo-macro
"[name] is the name of the function to define
[meta-data] is the map that defines the meta-data of the function"
[name meta-data]
(let [vals (gensym "label-")]
`(def ~name
~(with-meta `(fn [~vals] (eval nil))
meta-data))))
Calling (foo-macro fn-name {:foo "bar"})
should give you what you want: a function with (meta fn-name)
returning {:foo "bar"}
which, when printed, comes out something like #<user$fn_name user$fn_name@35df85a1>
.
Upvotes: 0