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

欢迎!请参阅关于页面以了解有关此功能的更多信息。

0 投票
Clojure

无法使用单个空选项序列或单个选项序列与默认条款结合使用case。

我期望
bq. (case 1 () :a :none)

返回 :none,但它失败并返回一个没有信息性的异常:“未处理的 clojure.lang.ArityException:传递给:core/max 参数数量不正确(-2)”

我期望 (case 1 () :a) 以“java.lang.IllegalArgumentException:没有匹配的分句”失败,但事实上它也以相同的异常失败:
"未处理的 clojure.lang.ArityException:传递给:core/max 参数数量不正确(-2)"

这似乎不一致,因为当其他选择存在时,传递空列表是可行的

bq. (case 1 () :a 2 :b :none)

返回预期结果:none

所附补丁在转换为case*之前删除包含空测试列表的测试条款对,并添加了测试。

8 答案

0 投票

评论者:chrisblom

错误,标题中重复了"single",

0 投票

评论者:alexmiller

在case中的空匹配列表看起来应该是错误 - 可能应该编译失败而不是忽略?

0 投票

评论者:chrisblom

在给出多个子句的情况下,目前支持选项列表为空,因此如果在一些情况下无法编译(即使用空列表),这将是个破坏性的变化。

这在1.8版本中工作正常

(案例1
() :never-happens
1 :ok
:default)
=> :ok

但这一点并不适用

(案例1
() :never-happens
:default)
=> 抛出异常 clojure.lang.ArityException: 传递给 core/max 的参数数量不正确(-2)

在我看来,仅在没有任何其他子句的情况下失败似乎非常不一致。

0 投票

评论者:bronsa

在case表达式中,空列表没有意义,因为匹配文本空列表的正确方式是 (case () (()) :empty)。我不认为让它不抛出异常有任何价值,我的意见是每当使用 () 时,编译时让 case 宏报错。

0 投票

评论者:alexmiller

() 现在不会匹配任何东西,因此在对 () 败诉不会破坏已经匹配的任何现有的 case。

我可以想象的一个情况是,有一个宏创建了一个 case,并可能以编程方式创建一个空的 case 列表?如下所示

(defmacro make-case [xs] `(defn ~'foo [e#] (case e# ~xs "matched" "nope")))

0 投票

评论者:chrisblom

我不是用它来匹配空列表,我是从 DSL 生成 case 表达式时遇到了这个边缘情况。
虽然这是一个病理案例,但我不同意说它没有意义,这里的空列表仅仅表示没有替代选项,
因此,该子句将不会匹配,且其结果表达式将不会执行。

我的观点是现在(在 clojure 1.8 中)这是被允许的

(case a
() :never-happens
1 :a
2 :b
:default)

相当于(因为空列表永远不会匹配)

(case a
1 :a
2 :b
:default)

但是:

(case a
() :never-happens
:default)

给出了一个无用的错误信息。

我认为它应该相当于:

(case a
:default)

因为拒绝 case 表达式中的空列表将是一个破坏性变革,
而在没有其他子句存在时拒绝空列表则是不一致的。

0 投票

评论者:chrisblom

??() 现在永远不会匹配任何东西,所以当 () 失败时不会损坏任何现有的匹配用例。??

由于Clojure中的case在版本<1.8时允许 ()(但当它是唯一条款时则不允许),让编译器拒绝它可能会破坏现有的代码。

??但我可以想象存在的一个情况是一个创建case的宏,可能会在程序中创建一个空的case列表????

这正是我遇到这个问题的方式

0 投票
参考:https://clojure.atlassian.net/browse/CLJ-2164(由 chrisblom 报告)
...