我想更好地理解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__
但我并不认为这是解决方案的一部分。
我该如何使这项工作?
答案 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))))