请分享您的想法,参与2024 Clojure 状态调查!

欢迎!请查看关于页面了解有关如何工作的更多信息。

+1
ClojureScript

这看起来像是 ClojureScript 1.11.54 中的一个 bug

(conj {} [:a 1] '([:b 2] [:c 3]) '([:d 4]))

在 JVM 上的 Clojure 中这是一个错误

cljs.user> (conj {} [:a 1] '([:b 2] [:c 3]) '([:d 4]))
{:a 1, :b 2, :c 3, :d 4}
cljs.user> :cljs/quit
nil
user> (conj {} [:a 1] '([:b 2] [:c 3]) '([:d 4]))
Execution error (ClassCastException) at user/eval17754 (REPL:25).
class clojure.lang.PersistentVector cannot be cast to class java.util.Map$Entry (clojure.lang.PersistentVector is in unnamed module of loader 'app'; java.util.Map$Entry is in module java.base of loader 'bootstrap')
事物 _工作_ 的事实并不意味着它是 bug。它也不意味着这是预期的行为并且可以依赖。在这种情况下,这很可能只是一个偶然。
在这种情况下,可行代码从数据角度来看意义不大。

Conj 可以将两个元素的向量连接到地图上,具有精确的语义。将向量列表连接到地图上不应该工作。

换句话说,(conj {} [[:a 1] [:b 2]]) 是可以接受的,因为我们需要连接两个向量的向量,并且结果是 {[:a 1] [:b 2]}

然而,(conj {} '([:a 1] [:b 2])) 不应该可以接受,因为它不是一个向量。

将 '([:d 4]) 仅连接到地图没有任何意义,并且不应该工作,但现在它在 CLJS 中工作。特别是由于 (conj [[:d 4]]) 不工作。

它几乎像是 CLJS 不关心它是元素的列表还是单个元素

    (conj {} [[:a 1] [:b 2]] '([:c 3] [:d 4]))
    => {[:a 1] [:b 2], :c 3, :d 4}
作者:
在某个特定的方式中,某事在某个地方能够正常工作,并不意味着它是有意义的。如果某事没有在文档中注明,那么它就是未被定义的行为。'不应该是这样的'——确实不是,如果它没有被记录下来。并不是每个无效或未定义的行为都会抛出异常,尤其是在 Clojure[Script] 中。
作者:
> 如果某事没有被在某个地方文档记录,那么按定义它是未定义的行为。

实际上恰恰相反。未定义的行为被语言指定为不可预测的。这就是我们知道为什么不应依赖它,但它不是一个错误。

我不知道你为什么尝试缓解这个问题。如果这是编译器中的一个错误,那么它可能是协议实现方面的问题,这可能会成为一个严重的问题。

作者:
> 未定义的行为被语言指定为不可预测的
如果你阅读更多与核心团队的讨论,未记录的通常被视为未定义的。至少在我的理解和记忆范围内,他们是这么看待这件事的。

例如,看看 Sean Corfield 的这一条优秀的评论:https://groups.google.com/g/clojure/c/yMHHHuK44pE/m/LeBhqdq6BQAJ
或者 Alex Miller 的这一条,明确讨论了特定情境下的未定义行为: https://groups.google.com/g/clojure/c/VwA2Un2NMxc/m/tptww3xZBwAJ
或者这条:https://groups.google.com/g/clojure/c/HtK4pqsr--8/m/KbWvq8CFCQAJ
等等。
还有许多许多其他的评论,遍布各个媒体。

> 未指定行为

Clojure 留下了很多未指定的地方。该语言本身没有任何规范或标准,只有文档(未记录下所有存在的东西)、一些规范定义和参考实现。早就已经明确指出,不是所有东西的指定是目标。

例如,调用 `keys` 或 `vals` 或遍历同一个映射对象将返回相同顺序的项目。但与第一个映射对象相等的不同映射对象可能会返回不同的顺序,CLJS 中的映射将几乎肯定返回与 CLJ 不同的顺序。

如果这是编译器的错误,它可能位于协议实现内,这可能会成为一个严重问题。

如果是这种情况,那将是另一个话题。

登录注册以回答这个问题。

...