请在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 不同的顺序中返回值。

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

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

登录注册以回答此问题。

...