Reputation: 2106
I have the following macro:
(defmacro my-macro [k]
`(do
(def pair
[
k
~(symbol (str "-" (name k)))]
)))
...which expands to:
(macroexpand-1 `(my-macro :n/k))
(do (def user/pair [user/k -k]))
...but instead I would like it to expand to
(do (def user/pair [:n/k -k]))
How can I make the macro keep the keyword and its namespace?
Thanks!
Upvotes: 0
Views: 359
Reputation: 5766
You need to escape k
from the syntax quote using ~k
:
(defmacro my-macro [k]
`(def ~'pair [~k ~(symbol (str "-" (name k)))]))
I've made a few other changes here as well:
(
or [
at the end of a line -- and put closing )
and ]
on the same line as the expression they close.do
is entirely superfluous here.If you want the macro to expand to (def pair ...)
, then you need to
~
)quote
the symbol pair
(i.e., 'pair
)Putting this together, you have ~'pair
. The reason you have to do this is because, in Clojure, `<symbol>
is read as (quote <current-namespace>/foo>)
, where <current-namespace>
stands for the current namespace. But def
doesn't take names that are namespaced. Hence the ~'
dance.
(But you probably want to parameterize on pair
anyway ... otherwise, it's not very useful to use my-macro
more than once per namespace.)
Overall, this seems like a very odd macro. I don't know what you're trying to accomplish, but I would probably take a different approach.
Upvotes: 1
Reputation: 29958
There are 2 things a bit confusing about your question & I misread it earlier.
'
with macroexpand-1
, not the back-tic `. The back-tick is normally used only in a macro definition to delineate a piece of "template code".k
, and the keyword you use in the example is :n/k
. These duplicate names will cause confusion.Let's restate the problem:
(ns clj.demo)
(defmacro my-macro [arg]
`(do
(def pair
[
arg
~(symbol (str "-" (name arg)))]
)))
(println (macroexpand-1 `(my-macro :n/k)))
;=> (do (def clj.demo/pair [clj.demo/arg -k]))
So we are in the clj.demo
namespace, which gets applied to the symbols pair
and arg
. We need to substitue the argument arg
using ~
:
(ns clj.demo)
(defmacro my-macro [arg]
`(do
(def pair
[
~arg
~(symbol (str "-" (name arg)))]
)))
(println (macroexpand-1 '(my-macro :n/k)))
;=> (do (def clj.demo/pair [:n/k -k]))
Which is what you want.
Upvotes: 1
Reputation: 91554
you can use the namespace
and name
function to extract the parts you want from the keyword passed in and combine them as required:
user> (defmacro my-macro [k]
`(do
(def pair
[~(keyword (str (namespace k) "/" (name k)))
~(symbol (str "-" (name k)))])))
#'user/my-macro
user> (macroexpand-1 `(my-macro :n/k))
(do (def user/pair [:n/k -k]))
Upvotes: 1