暧昧的守卫模式

时间:2016-02-19 16:30:26

标签: pattern-matching ocaml

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以使模糊性消失,但请注意这只是一个简化的例子。

1 个答案:

答案 0 :(得分:1)

警告是指人们不知道when警卫不属于该模式,并且假设A s, _ | _, A s when s = ""与语法无效的A s, _ | (_, A s when s = "")相同。

保持警告似乎是一个好主意,尽管如果明确的括号阻止警告会很好,例如(A s, _ | _, A s) when s = ""

您建议编译器应该比普通读者更聪明,并根据非显而易见的规则抑制警告。换句话说,你的推理是正确的,但对于习惯依赖警告的程序员来说,这是一个太多的开销。