如何将多个条件模式与一个结果匹配?

How to match multiple conditional patterns with one result?

尝试编译以下函数会导致错误:

let balance (left : 'a t) (ele : 'a) (right : 'a t) : 'a t =
  match left,ele,right with
  | N (d',N (_,a,x,b),y,c),z,d when d' - depth d > 1 && ele < y
  | N (d',a,x,N (_,b,y,c)),z,d when d' - depth d > 1 && ele > x
  | a,x,N (d',N (_,b,y,c),z,d) when d' - depth a > 1 && ele < z
  | a,x,N (d',b,y,N (_,c,z,d)) when d' - depth a > 1 && ele > y
      -> new_node (new_node a x b) y (new_node c z d)
  | _ -> new_node left ele right

但是,以下两个函数都可以正常编译:

let balance (left : 'a t) (ele : 'a) (right : 'a t) : 'a t =
  match left,ele,right with
  | N (d',N (_,a,x,b),y,c),z,d
  | N (d',a,x,N (_,b,y,c)),z,d
  | a,x,N (d',N (_,b,y,c),z,d)
  | a,x,N (d',b,y,N (_,c,z,d))
      -> new_node (new_node a x b) y (new_node c z d)
  | _ -> new_node left ele right
let balance (left : 'a t) (ele : 'a) (right : 'a t) : 'a t =
  match left,ele,right with
  | N (d',N (_,a,x,b),y,c),z,d when d' - depth d > 1 && ele < y
      -> new_node (new_node a x b) y (new_node c z d)
  | _ -> new_node left ele right

如何获得第一个块中指定的行为?显然,我可以将第七行复制到前面的每个模式,但我不想这样做。

没错,这是 OCaml 模式的限制。

当你这样写的时候:

match x with
| 1
| 2 -> f x

你实际上只写了一个看起来像这样的模式:

match x with
| (1 | 2) -> f x

所以这个(如果允许的话):

match x with
| 1 when a
| 2 when b -> f x

相当于这样的东西:

match x with
| (1 when a | 2) when b -> f x

换句话说,您要做的是将 when 子句添加到模式的中间。这不受支持。它们只是 match 的特征,而不是一般模式的特征。

作为 Jeffrey Scofield 已经说过的内容的补充,请注意以下陷阱。

match 42 with 
| 1 
| n when n mod 2 = 0 -> "foo" 
| n -> "bar"

或等效地:

match 42 with 
| (1 | n) when n mod 2 = 0 -> "foo" 
| n -> "bar"

两者都会让您出现此错误:

Error: Variable n must occur on both sides of this | pattern

when 条件保护必须为 任一 模式工作。这就是以下内容起作用的原因。

match (3, 2) with 
| (1, n) 
| (3, n) when n mod 2 = 0 -> "foo" 
| n -> "bar"

等价于:

match (3, 2) with 
| ((1, n) | (3, n)) when n mod 2 = 0 -> "foo" 
| n -> "bar"

如果使用与 | 连接的模式将相同的名称绑定到不同的值,请做好编译器警告的准备。