如何编写一个打印自己后缀的嵌套宏?

时间:2012-09-24 21:39:04

标签: clojure macros

我想更好地理解listing 13.3 in The Joy of Clojure。它是一个生成其他宏的宏(就像在Clojure 1.4中实现原始数组函数一样)。

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

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

为了解决这个问题,我还尝试将#添加到局部变量中,结果与上面类似但是使用&#34; auto&#34;名称,例如local-name__1127__auto__但我并不认为这是解决方案的一部分。

我该如何使这项工作?

1 个答案:

答案 0 :(得分: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))))