OCaml 的 future 4.03 版本增加了一个新警告,57
, 防止 ambiguous guarded pattern .也就是说,问题在于带有 when
的 or 模式。子句,如果 or-pat 的第一部分匹配,但 when
评估为 false
,完整的模式将被丢弃,尽管 or-pat 的另一个变体可能会成功。例如,在以下代码中,ko
将绑定(bind)到1
,这可能令人惊讶:
type t = A of string | B of string
let bad x y =
match x,y with
| A s, _ | _, A s when s = "foo" -> 0
| _, _ -> 1
let ok = bad (A "foo") (A "bar")
let ko = bad (A "bar") (A "foo")
在 4.03 中,OCaml 会提示
Warning 57: Ambiguous guarded pattern, variable s may match different or-pattern arguments
,建议您检查一下您是否真的有意这样做。但是,警告在以下定义中模式匹配的第二行也处于事件状态:
let f x y =
match x,y with
| A _, A _ -> 0
| A s, _ | _, A s when s = "foo" -> 1
| _ -> 2
在这里,我认为不会出现歧义,因为
A _, A _
由第一行匹配,因此,如果程序到达这一点,则 or-pattern 的组件最多可以匹配。这个推理正确吗?如果答案是肯定的,我还想知道是否可以在此特定分支上消除此警告。确实,我可以做
match [@warning "-57"] x,y with
,但是如果稍后有人在那里引入另一个模棱两可的模式,这将使警告静音。我试图将属性放在模式级别( | A s, _ | _, A s [@warning "-57"] when s = "foo"
),但这没有效果。注意:我知道在这种特定情况下,我可以用
| A s, B _ | B _, A s when s = "foo"
替换包罗万象的内容。使歧义消失,但请考虑这只是一个简化的例子。
最佳答案
该警告适用于不知道 when
的人守卫不是模式的一部分,想象一下 A s, _ | _, A s when s = ""
与 A s, _ | (_, A s when s = "")
相同这在语法上是无效的。
保留警告似乎是个好主意,尽管如果显式括号阻止它会很好,例如(A s, _ | _, A s) when s = ""
.
您建议编译器应该比普通读者更聪明,并根据不明显的规则抑制警告。换句话说,您的推理是正确的,但对于习惯于依赖警告的程序员来说,开销太大了。
关于pattern-matching - 模棱两可的守卫模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35510124/