以下是代码:
(defmacro inspect-caller-form [& args]
{:form (quote `(inspect-caller-form ~@args))})
(inspect-caller-form 1 2 3)
和错误:
CompilerException java.lang.RuntimeException: Unable to resolve symbol: args in this context, compiling:(/Users/kaiyin/personal_config_bin_files/workspace/cina/src/cina/ref_types.clj:406:5)
但如果我在quote
之前移动语法引用,事情似乎有效:
(defmacro inspect-caller-form [& args]
{:form `(quote (inspect-caller-form ~@args))})
(inspect-caller-form 1 2 3)
为什么?
答案 0 :(得分:2)
通过简单地在repl上评估它们并查看它们评估的形式,它通常可以帮助调试语法引用问题。在这种情况下,我们可以看到第一个示例扩展为读取语法引用的未评估结果。这是因为语法引用是clojure中为数不多的读取器宏之一,并且可以在宏扩展时开始工作。然后您的报价电话会阻止它进一步扩展。所以语法引用永远不会完成它的工作。
user> (let [args [1 2 3]]
(quote `(inspect-caller-form ~@args)))
(clojure.core/seq (clojure.core/concat
(clojure.core/list
(quote user/inspect-caller-form))
args))
虽然第二个允许语法引用表单完成评估,并产生一个引用调用的结果。因此,最终结果是一个单引号列表,其值已经拼接到其中。
user> (let [args [1 2 3]]
`(quote (inspect-caller-form ~@args)))
(quote (user/inspect-caller-form 1 2 3))
在语法引用中使用引用实际上是编写宏的有用技巧,它可以将新符号直接引入调用者的范围,称为符号捕获。