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

欢迎!请查看关于页面获取更多关于如何使用本站的信息。

+1
编译器

Clojure编译器在编译函数调用时似乎使用了vars的: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在由loader 'app'组成的未命名模块中)

在解析对foo的调用时,编译器似乎使用了未评估的参数列表形式(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

Var arglists应该是一个字面量向量列表,例如

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

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

错误仅在变量在其自身体内部进行递归调用时出现。
我不确定关于:arglists有什么或多少文档,但我认为你可以假设:arglists应该是defn中的数据。
快速在Github中进行代码搜索显示,野外有几个这样的实例,包括核心Clojure库

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

没有明确的文档或编译器警告指明只允许在该特定元数据槽中包含字面引号列表,因此我认为人们会自然而然地做出其他假设。
...