2024 年 Clojure 状态调查中分享您的想法!

欢迎!有关如何使用本站的更多信息,请参阅 关于 页面。

+1
编译器

Clojure 编译器在编译函数调用时似乎使用 vars 的 :arglists 元数据,这与在其 defn 形式的体内以动态指定的元数据递归调用的函数冲突。
一个简单的示例

(defn foo
  {:arglists (list '[n])}
  [n]
  (if (even? n)
    n
    (foo (dec n))))

导致编译错误

语法错误(ClassCastException),在 (REPL:6:5) 编译 foo 时。无法将 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))

1 个答案

0

变量 arglists 应该是一个向量列表的文本形式,例如

:arglists '([shape] [shape shape-attrs])
我没有在任何地方找到这种限制的提及,那么这是否意味着任何通过程序定义的arglist *必须* 在创建变量后通过`alter-meta!`进行指定?

注意,以下代码可以正确编译和运行
```
(defn draw
  {:arglists (list ['shape shape-attrs])}
  ([shape attrs]
   :ok))
```

错误只会在变量自身内部进行递归调用时出现。
by
我不知道关于:arglists是否有太多或任何文档,但我认为你可以假设:arglists应该是defn中的数据。
by
在GitHub上快速搜索代码,显示了一些野外的情况,包括一个核心Clojure库

https://github.com/clojure/data.xml/blob/e6522752bd9d66b0d6c1255f1a706433975a92cc/src/main/clojure/clojure/data/xml.clj#L135

没有明确的文档或编译器警告,表示只能在该特定元数据槽中使用字面常量引用列表,我认为人们会自然而然地做出其他假设。
...