OCaml的未来4.03版本添加了一个新警告57
,以防止ambiguous guarded pattern。也就是说,问题是在带有when
子句的or-pattern上,如果or-pat的第一部分匹配,但when
评估为false
,则完整模式将被丢弃,虽然or-pat的另一种变体可能会成功。例如,在以下代码中,ko
将绑定到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"
替换catch-all以使模糊性消失,但请注意这只是一个简化的例子。
答案 0 :(得分:1)
警告是指人们不知道when
警卫不属于该模式,并且假设A s, _ | _, A s when s = ""
与语法无效的A s, _ | (_, A s when s = "")
相同。
保持警告似乎是一个好主意,尽管如果明确的括号阻止警告会很好,例如(A s, _ | _, A s) when s = ""
。
您建议编译器应该比普通读者更聪明,并根据非显而易见的规则抑制警告。换句话说,你的推理是正确的,但对于习惯依赖警告的程序员来说,这是一个太多的开销。