嵌套引号中的IllegalStateException并取消引用

时间:2015-05-23 20:32:24

标签: clojure macros

这是一个来自clojure的喜悦的例子:

(let [x 9, y '(- x)]
  (println `y)
  (println ``y)
  (println ``~y)
  (println ``~~y))

来自repl的输出:

typedclj.macros/y
(quote typedclj.macros/y)
typedclj.macros/y
(- x)

如果我重新排列引用/取消引用的顺序,结果仍然相同(我想知道为什么):

(let [x 9, y '(- x)]
  (println `y)
  (println ``y)
  (println `~`y)
  (println `~`~y))

但如果我把波浪号放在前面:

(let [x 9, y '(- x)]
  (println `y)
  (println ``y)
  (println `~`y)
  (println ~``~y))

我收到一个奇怪的错误:

CompilerException java.lang.IllegalStateException: Attempting to call unbound fn: #'clojure.core/unquote, compiling:(/Users/kaiyin/personal_config_bin_files/workspace/typedclj/src/typedclj/macros.clj:1:25) 

为什么我会收到此错误?

1 个答案:

答案 0 :(得分:1)

简短回答:你在unquote之外尝试syntax-quote,这没有意义。

更多详情:

此错误是从最终的println生成的。观察

(println ~``~y) 

扩展为

(println (unquote (syntax-quote (syntax-quote (unquote y))))

这种情况发生在~并且反引号字符是读者宏。扩展unquote实际上不是正常函数或宏。它是一种特殊形式,仅在syntax-quote内定义。您可以在LispReader.java中的编译器源中看到这一点。当你在syntax-quote形式之外使用它时,读取器宏仍然发生但是没有“unquote”这样的功能。 core.clj中只有一个裸(def unquote)(第一个定义)。

当您执行def之类的操作时,最终会得到一个var,其初始绑定是类cloure.lang.Unbound的一个实例(它是clojure.lang.Var上的constructors之一这个子类clojure.lang.AFn但没有指定任何arities;所以每次调用它都会调用throwarity,给你这个例外。