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}
by
某个以特定方式工作的事物不一定有意义。如果某事物没有文档记载,则其行为是未定义的。不应该这么好”——如果它没有记录,确实不是好事情。并非每个无效或未定义的行为都会抛出异常,尤其是在Clojure[Script]中。
by
> 如果某事物没有文档记载,那么它就是未定义的行为。

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

您所提到的行为是不确定行为,这通常是由于忽略了文档或实现中的某个环节。在这种情况下,我怀疑是后者。

但我不知道为什么您试图缓解这个问题。如果这是个编译器的bug,那么它可能在协议实现中,这可能是一个严重的问题。
by
> 未定义的行为是不可预知的

如果您阅读了与核心团队的更多讨论,未记录的一般被视为未定义的。至少在我的理解和记忆中是这样的。
例如,您可以参阅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 中的映射几乎肯定会在不同的顺序返回值。

如果这是一个编译器的错误,它可能存在于协议实现中,这可能会引起严重问题。

如果是这种情况,那将是一个不同的讨论。

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

...