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

欢迎!请参阅关于 页面,了解更多关于其工作方式的信息。

0
Clojure
clojure.set/intersection,根据其意图和文档,旨在对两个集合执行操作。然而,它有时允许(并在非集合参数上返回正确的操作)非集合参数。这产生了一些困惑,误解了非集合参数不应使用的意图。

以下是一个使用 Set 与 KeySeq 的示例
如果恰好存在交集,您将得到一个结果。这可能导致编写代码的人认为这是可以接受的,或者没有注意到他们使用了不兼容的数据类型。然而,一旦交集为空,就会产生一个适当的类型错误,即意外地因为 clojure.core/disj 的第一个参数应该是集合。


user=> (require '[clojure.set :refer [intersection]])
nil
user=> (intersection #{:key_1 :key_2} (keys {:key_1 "na"}))   ; 此操作可行,但不应该
(:key_1)
user=> (intersection #{:key_1 :key_2} (keys {:key_3 "na"}))   ; 此操作失败,因为 intersection 假设第二个参数是集合
ClassCastException clojure.lang.APersistentMap$KeySeq cannot be cast to clojure.lang.IPersistentSet  clojure.core/disj (core.clj:1449)

(disj (keys {:key_1 "na"}) #{:key_1 :key_2})   ; intersection 做出的假设
ClassCastException clojure.lang.APersistentMap$KeySeq cannot be cast to clojure.lang.IPersistentSet  clojure.core/disj (core.clj:1449)


对一个明显旨在用于特定类的库进行类型安全检查似乎是一件负责任的事情。它可以防止具有缺陷的代码不被知不觉地接受为正确,直到正确的数据出现并触发出错。

5 个答案

0

由 jafingerhut 发布的评论

CLJ-810 类似,但那是一个关于 clojure.set/difference 函数的功能。那个被评论拒绝了,“如果未传递集合,则 set/difference 的行为未文档记录”。我不知道内核团队将如何判断这个票据,但还想提供一些历史。

Dynalint(链接:1)以及我认为 Dire(链接:2)可以被用来为主函数添加动态参数检查。

(链接:1) https://github.com/frenchy64/dynalint
(链接:2) https://github.com/MichaelDrogalis/dire

0

评论者:alexmiller

由于 set 对于集合操作更快,我认为我们实际上可以在一些之前可能没有检查的地方添加对集合的检查。所以,值得用全新的眼光来看待这个问题。

0

评论者:jawolfe

回想起2009年,我给集合函数提交了一个补丁,加入了显式的 set? 检查,Rich 的回复是:“这些函数恰好能在第二个参数不是集合时工作,这是一个实现上的特性,而不是接口的承诺,因此我不赞成进行 set? 测试或任何对此的适应。”不过,不确定这个结论是否仍然准确。

0

由 jafingerhut 发布的评论

如果您需要 clojure.set 函数的现成兼容替代品,这些函数的行为相同,但它们为您提供的参数执行运行时类型检查,如果类型不正确(例如,对于并集、交集、差集、子集?和超集?不是集合),则抛出异常,请考虑使用 fungible 库:https://github.com/jafingerhut/funjible

0
参考: https://clojure.atlassian.net/browse/CLJ-1682(由 vhouseman 报告)
...