请在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' 加载器的匿名模块中)

编译器似乎在使用未评估的 arglist 形式 (list (quote [n])) 解析对 foo 的调用,由于符号 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是否有太多或任何文档,但我认为你可以在defn中将:arglists视为数据。
快速在GitHub上搜索代码,显示了一些此类实例,包括核心Clojure库

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

没有明确的文档或编译器警告,只允许在特定的元数据槽中引用文献列表,我相信人们会自然而然地做出相反的假设。
...