Reputation: 27306
I am trying to define a function that will create a macro and am running into problems when I try to dynamically supply the macro's name. Here's narrowed-down code that exemplifies the issue I am facing:
(defn create-times-macro [n]
(defmacro thatManyTimes [a]
`(* ~n ~a)))
(create-times-macro 2)
(thatManyTimes 3) ;; evals to 6
So far so good. Now say I want to supply the macro's name as a parameter:
(defn create-times-macro [macroName n]
(defmacro macroName [a]
`(* ~n ~a)))
(create-times-macro (symbol "multiplyBy") 3)
(multiplyBy 3) ;; fails with unable to resolve symbol multiplyBy
(create-times-macro "multiplyBy" 3)
(multiplyBy 3) ;; same failure
Upvotes: 1
Views: 100
Reputation: 33657
It seems that you are confused about the use of macros.
All these points suggest the fact that macros are compile time thing where as functions are run-time thing. The usual direction is compile time to run-time where as the last point is about going from runtime to compile time.
Your first code example works in REPL but it won't work in a compiled JAR. In REPL you are in a compile-time->run-time->print->loop and becoz of the loop you sort of go back to compile->time from run-time and that is why the last point work in REPL. In compiled code you will only have, well, compiled code and there is only runtime world, unless you use eval
in your code which can bring you back to compile time.... Wait my head hurts but I hope this make things clear :)
Upvotes: 4
Reputation: 3752
You don't need macro in this case. Functions are suitable in most cases and they have more abilities than macros. For example, if you create it as function
(defn create-times-fn [n]
(fn [a]
(* n a)))
you would get the same result
(def three-times (create-times-fn 3))
(three-times 2)
=> 6
or
(let [three-times (create-times-fn 3)]
(three-times 2))
And you can pass it as argument to other functions
(map (create-times-fn 2) (range 5))
=> (0 2 4 6 8)
or return it as result or compose it with other functions. You lose all these things with macros.
Upvotes: 1
Reputation: 8633
Not sure if this is the best way to do it, but it works:
=> (defmacro create-times-macro [macroName n]
(let [the-name (symbol macroName)]
`(defmacro ~the-name [a#]
(* ~n a#))))
#'user/create-times-macro
=> (create-times-macro "hi" 3)
#'user/hi
=> (hi 4)
12
Upvotes: 1