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 的调用时,编译器似乎使用了未求值的参数列表形式 (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 应该是向量列表的文[len]字列表,例如

:arglists '([shape] [shape shape-attrs])
 
我找不到任何地方提到这个限制,那么是否意味着任何通过编程方式定义的 arglists *都必须* 在变量创建后通过 `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

如果没有明确的文档或编译器警告指明在那个特定的元数据槽位只允许使用字面引号的列表,那么人们认为否则是相当自然的。
...