Попытка скомпилировать следующую функцию вызывает ошибку:
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
, а не паттернов в целом.
В дополнение к тому, что уже сказал Джеффри Скофилд, остерегайтесь следующей ловушки.
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"
Будьте готовы к предупреждениям компилятора, если вы привязываете одно и то же имя к разным значениям, используя шаблоны, объединенные с помощью |
.
Было бы очень хорошо, если бы вы могли включить ошибку, которую вы получаете. Когда я пробую первую функцию на try.ocamlpro.com, она дает мне
Syntax Error
, и эта синтаксическая ошибка возникает из-за неправильного использованияwhen
.