Clojure 函数,该函数使用作为参数提供的宏名称创建宏

Clojure 函数,该函数使用作为参数提供的宏名称创建宏,clojure,Clojure,我试图定义一个函数来创建宏,但当我试图动态提供宏的名称时遇到了问题。以下是我面临的问题的简化代码: (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]

我试图定义一个函数来创建宏,但当我试图动态提供宏的名称时遇到了问题。以下是我面临的问题的简化代码:

(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

不确定这是否是最好的方法,但它是有效的:

=> (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

不确定这是否是最好的方法,但它是有效的:

=> (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

在这种情况下,不需要宏。函数在大多数情况下都是合适的,它们比宏具有更多的功能。例如,如果将其创建为函数

(defn create-times-fn [n]
  (fn [a]
    (* n a)))
你会得到同样的结果

(def three-times (create-times-fn 3))

(three-times 2)
=> 6

您可以将其作为参数传递给其他函数

(map (create-times-fn 2) (range 5))
=> (0 2 4 6 8)

或者将其作为结果返回,或者将其与其他函数组合。宏会丢失所有这些内容。

在这种情况下,不需要宏。函数在大多数情况下都是合适的,它们比宏具有更多的功能。例如,如果将其创建为函数

(defn create-times-fn [n]
  (fn [a]
    (* n a)))
你会得到同样的结果

(def three-times (create-times-fn 3))

(three-times 2)
=> 6

您可以将其作为参数传递给其他函数

(map (create-times-fn 2) (range 5))
=> (0 2 4 6 8)

或者将其作为结果返回,或者将其与其他函数组合。宏会丢失所有这些东西。

您似乎对宏的使用感到困惑

创建函数的宏-确定 创建另一个宏的宏-确定 创建宏的函数-不正常不常见。 所有这些都表明宏是编译时的,而as函数是运行时的。通常的方向是从编译时到运行时,最后一点是从运行时到编译时


您的第一个代码示例在REPL中工作,但在编译的JAR中不工作。在REPL中,您处于一个编译时->运行时->打印->循环中,由于这个循环,您可以从运行时返回编译->时间,这就是为什么最后一点在REPL中工作。在编译代码中,您将只有编译代码,并且只有运行时世界,除非您在代码中使用eval,这可以使您回到编译时。。。。等等,我的头很痛,但我希望这能说明问题:

你似乎对宏的使用感到困惑

创建函数的宏-确定 创建另一个宏的宏-确定 创建宏的函数-不正常不常见。 所有这些都表明宏是编译时的,而as函数是运行时的。通常的方向是从编译时到运行时,最后一点是从运行时到编译时


您的第一个代码示例在REPL中工作,但在编译的JAR中不工作。在REPL中,您处于一个编译时->运行时->打印->循环中,由于这个循环,您可以从运行时返回编译->时间,这就是为什么最后一点在REPL中工作。在编译代码中,您将只有编译代码,并且只有运行时世界,除非您在代码中使用eval,这可以使您回到编译时。。。。等等,我的头很痛,但我希望这能说明问题:

这是一个缩小的例子。这不是我面临的实际情况。我只是举了一个简单的例子来说明我想做什么。对此我很抱歉。我只是不明白宏创建另一个宏的目的。这是一个缩小的例子。这不是我面临的实际情况。我只是举了一个简单的例子来说明我想做什么。对此我很抱歉。我只是不明白创建另一个宏的宏的用途。你们确定它能在罐子里工作吗?请参阅下面的@Ankur-answer@Blacksad:这将在JAR中工作,因为它是创建宏的宏,而不是创建宏的函数。我明白了。谢谢你的提醒!你确定它在罐子里能用吗?请参阅下面的@Ankur-answer@Blacksad:这将在JAR中工作,因为它是创建宏的宏,而不是创建宏的函数。我明白了。谢谢你的提醒!