2

我试图更好地理解Clojure 中的清单 13.3。它是一个生成其他宏的宏(很像 Clojure 1.4 中原始数组函数的实现方式)。

我想编写一个宏,在运行时只打印生成的宏的后缀。IE

user=> (nested-macro joe)
user=> (nested-macro-named-joe)
hello from joe
nil

我无法完成这项工作。

这是我尝试过的:

尝试 1

(defmacro nested-macro [name]
  `(defmacro ~(symbol (str "nested-macro-named-" name))
     []
     `(println "hello from " ~name)))

输出:

hello from #<core$name clojure.core$name@502c06b2>

尝试 2

(defmacro nested-macro [name]
  (let [local-name name]
    `(defmacro ~(symbol (str "my-custom-macro-named-" ~local-name))
       []
       `(println "hello from " ~local-name))))

错误

IllegalStateException Attempting to call unbound fn: #'clojure.core/unquote clojure.lang.Var$Unbound.throwArity (Var.java:43)

尝试 3:

(defmacro nested-macro [name]
  (let [local-name name]
    `(defmacro ~(symbol (str "nested-macro-named-" name))
       []
       `(println "hello from " ~(symbol local-name)))))

编译器错误:

CompilerException java.lang.RuntimeException: No such var: joy.dsl/local-name

只是为了它,我还尝试添加#到局部变量,结果与上述类似,但使用“自动”名称,例如local-name__1127__auto__我不认为这是解决方案的一部分。

我怎样才能使这项工作?

4

1 回答 1

3

要知道宏出了什么问题,我总是使用macroexpand-1.

从你的第一个例子:

(macroexpand-1 '(nested-macro joe))

结果是:

(clojure.core/defmacro nested-macro-named-joe [] 
  (clojure.core/seq 
    (clojure.core/concat 
      (clojure.core/list (quote clojure.core/println)) 
      (clojure.core/list "hello from ") 
      (clojure.core/list clojure.core/name))))

如果您查看最后一个参数,它表明您正在使用 clojure.core/name,这可能不是您想要的,因为您实际上想要名为“name”的参数。

要修复它,只需在name参数中添加另一个取消引号,但由于名称参数实际上是一个符号,您真正想要的是获取它的名称,如下所示:

(defmacro nested-macro [the-name]
  `(defmacro ~(symbol (str "nested-macro-named-" the-name))
     []
     `(println "hello from " ~~(name the-name))))
于 2012-09-24T22:10:14.023 回答