2013-02-26 57 views
1

我想定义一个函数,将创建一个宏,并在我试图动态提供宏的名称时遇到问题。这里列出了我正在面临的问题的缩小代码:功能,创建宏作为参数提供的宏名称

(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 

回答

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 
+0

你确定它能在JAR中工作吗?请参阅下面的@Ankur答案。 – Blacksad 2013-02-26 23:04:02

+0

@Blacksad:这将在JAR中工作,因为它是宏创建宏而不是创建宏的函数。 – Ankur 2013-02-27 04:25:52

+0

我明白了。感谢您的领导! – Blacksad 2013-02-27 05:18:26

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) 

或退货作为结果或与其他功能组合。你用宏丢失了所有这些东西。

+0

这是一个缩小的例子。这不是我正面临的实际情况。我只是想出了一个简单的例子来说明我正在尝试做什么。 – 2013-02-26 18:00:59

+0

对不起。我只是看不到创建另一个宏的宏的目的。 – mobyte 2013-02-27 02:55:57

4

看来你对使用宏感到困惑。

  • 其中创建一个功能宏 - 行
  • 其中创建另一个宏宏 - 行
  • 函数创建宏 - 不OK(不常见和通常)。

所有这些观点都表明,宏是编译时的事情,其中​​函数是运行时的事情。通常的方向是编译时间到运行时间,最后一点是从运行时间到编译时间。

你的第一个代码示例在REPL中有效,但它在编译的JAR中不起作用。在REPL中,您处于编译时 - >运行 - >打印 - >循环,因此您可以从循环中返回编译 - >时间,这就是为什么最后一点在REPL中起作用的原因。在编译后的代码中,只有编译代码,并且只有运行时环境,除非您在代码中使用eval,这可以使您重新编译时间....等待我的头疼,但我希望这可以让事情变得清晰: )