模糊的守卫模式匹配

4
OCaml的未来版本4.03添加了一个新警告57,以防止模糊的守卫模式。也就是说,在带有when子句的或模式中,如果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 _会被第一行匹配,因此如果程序到达此点,则至多只能匹配或模式的一个组件。这种推理正确吗?

如果答案是肯定的,我想知道是否可以在特定分支上消除此警告。实际上,我可以使用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,以消除歧义,但请考虑这只是一个简化的例子。

1个回答

2
警告是为不熟悉模式匹配中when守卫不是模式的一部分并且认为A s, _ | _, A s when s = ""A s, _ | (_, A s when s = "")相同,但语法上是无效的人发出的。建议保留此警告,尽管如果使用显式括号,例如(A s, _ | _, A s) when s = "",则可以避免此警告。您的建议是编译器应该比普通读者更聪明,并基于非明显规则抑制警告。换句话说,您的推理是正确的,但对于习惯依靠警告的程序员来说,这会增加太多开销。

我并不是在建议编译器应该更聪明,我只是想有一种方法来告诉它:“对于这个特定的模式,相信我,我知道我在做什么”,而不必放弃整个模式匹配表达式的警告。 - Virgile
我认为一条指令来在本地打开或关闭警告会很有用。 - Martin Jambon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接