Clojure 编译器在编译函数调用时似乎会使用 var 的 :arglists 元数据,这种方式与它们体中递归调用的函数相冲突,因为递归调用的函数使用了动态指定的元数据。
一个最小化示例
(defn foo
{:arglists (list '[n])}
[n]
(if (even? n)
n
(foo (dec n))))
这会导致编译错误
语法错误(ClassCastException)在编译 foo 时(REPL:6:5)。无法将 clojure.lang.Symbol 类型的实例转换为 clojure.lang.IPersistentVector 类型的实例(clojure.lang.Symbol 和 clojure.lang.IPersistentVector 在 'app' 加载器的未命名模块中)
编译器似乎在解析对 foo 的调用时使用了 arglist 的未评估形式 (list (quote [n]))
,由于 list
符号不是预期的参数向量,导致抛出异常。
这是这种问题可能发生的稍微更真实的示例
(def ^:private shape-attrs
'{:keys [height width color]})
(defn draw
{:arglists (list ['shape]
['shape shape-attrs])}
([shape]
(draw shape {:color "black"}))
([shape attrs]
:ok))