我正在尝试定义一个函数,该函数将创建一个宏,并在尝试动态提供宏名称时遇到问题。这里的缩小代码举例说明了我面临的问题:
(defn create-times-macro [n]
(defmacro thatManyTimes [a]
`(* ~n ~a)))
(create-times-macro 2)
(thatManyTimes 3) ;; evals to 6
到目前为止一切顺利。现在说我想提供宏的名称作为参数:
(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
答案 0 :(得分:4)
您似乎对使用宏感到困惑。
所有这些都表明宏是编译时间的事实,因为函数是运行时的东西。通常的方向是编译时到运行时,最后一点是从运行时到编译时。
您的第一个代码示例适用于REPL,但它不适用于已编译的JAR。在REPL中,您处于编译时 - >运行时 - > print->循环和循环的becoz,您可以从运行时返回编译 - >时间,这就是为什么最后一点在REPL工作。在编译的代码中,你只有编译代码,并且只有运行时世界,除非你在你的代码中使用eval
,这可以让你回到编译时间....等我的头痛,但我希望这把事情弄清楚:)
答案 1 :(得分:1)
不确定这是否是最好的方法,但它确实有效:
=> (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
答案 2 :(得分:1)
在这种情况下你不需要宏。函数在大多数情况下都适用,并且它们具有比宏更多的能力。例如,如果您将其创建为函数
(defn create-times-fn [n]
(fn [a]
(* n a)))
你会得到相同的结果
(def three-times (create-times-fn 3))
(three-times 2)
=> 6
或
(let [three-times (create-times-fn 3)]
(three-times 2))
你可以把它作为参数传递给其他函数
(map (create-times-fn 2) (range 5))
=> (0 2 4 6 8)
或将其作为结果返回或与其他功能组合。你用宏丢失了所有这些东西。