2024 年 Clojure 状态调查! 中分享您的观点。

欢迎!请查阅 关于 页面了解更多关于如何使用本网站的信息。

+1
编译器

Clojure 编译器在编译函数调用时似乎会使用 var 的 :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 在 '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])
by
我在任何地方都没找到这个限制的说明,那么在变量创建后,是否必须通过`alter-meta!`指定任何通过程序定义的arglists?

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

错误仅在变量在其自身体内进行递归调用时出现。
by
我不知道是否有关于:arglists的很多或任何文档,但我认为你可以假设:arglists应该在defn中的数据。
by
在Git(Hub上进行快速代码搜索显示了几个这样的实例,包括核心Clojure库

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

由于缺乏明确的文档或编译器警告,只有字面量引用列表被允许在该特定元数据槽中,我相信人们会自然而然地假设否则。
...