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

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

+1
编译器

Clojure 编译器似乎会在编译函数调用时使用 vars 的 :arglists 元数据,方法与它们体内的函数递归调用与其动态指定的元数据冲突。
一个简单的例子

(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

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

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

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

只有在 var 的体内对其自身的递归调用时才会出现错误。
by
我不知道是否有关于 :arglists 的文档,但我想你可以假设 :arglists 应该是 defn 中的数据。
by
Github 上的快速代码搜索显示了几个此类实例,包括核心 Clojure 库

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

如果没有明确的文档或编译器警告,说明仅允许在该特定元数据槽中允许字面引号列表,那么人们自然会对其他方法表示怀疑。
by
...