Как обнаружить коммутативные шаблоны в Ocaml, используя сопоставление с шаблоном? - PullRequest
7 голосов
/ 09 мая 2011

Мне нужно обнаружить коммутативный шаблон в одной из моих функций. Я думал, что написание следующего сделает работу:

let my_fun a b = match a,b with
  (*...*)
  | a,b
  | b,a when is_valid b -> process b  (***)
  (*...*)

Это не работает, и Ocaml жалуется на , этот подшаблон не используется предупреждение для линии, отмеченной (***).

1) Может кто-нибудь объяснить мне, что пытается сказать это предупреждение и почему это не работает?

2) Как я могу на самом деле написать это элегантно, не используя if then else, учитывая тот факт, что я хочу узнать, какой аргумент is_valid?

2) Можно ли получить намеченную функциональность, используя только сопоставление с образцом и без повторения when is_valid b -> process b, как это происходит ниже?

let my_fun a b = match a,b with
  (*...*)
  | a,b when is_valid b -> process b
  | b,a when is_valid b -> process b 
  (*...*)

Edit:

В моем конкретном примере a и b являются парами. Функция немного сложнее, но следующий случай иллюстрирует случай:

let f a b = match a,b with
  | (a1,a2),(b1,b2)
  | (b1,b2),(a1,a2) when b1 = b2 -> a1 + a2

Вызов f (1,1) (1,2) приведет к неудачному совпадению с шаблоном. Я знаю, понимаю почему (благодаря ответам ниже) и понимаю, как я могу заставить его работать, если у меня есть разные конструкторы для каждого элемента (как в ответе Ашиша Агарвала). Можете ли вы предложить способ заставить его работать в моем случае?

Ответы [ 2 ]

7 голосов
/ 09 мая 2011

Сопоставление выполняется сначала путем сопоставления с шаблоном, а если это удается, то путем оценки условия с присоединенной средой из этого сопоставления с шаблоном. Поскольку a,b всегда будет связываться, это единственный используемый случай, и компилятор правильно сообщает, что b,a никогда не используется. Вам придется повторить эту строку,

let my_fun a b = match a,b with
  | a,b when is_valid b -> process b
  | b,a when is_valid b -> process b

Ваш метод мог бы работать, если вы не выполняли сопоставление с переменными, но с некоторым вариантом, например,

let my_fun a b = match a,b with
  | a, `Int b
  | `Int b, a when is_valid b -> process b

Редактировать: Думайте о нескольких шаблонах, используя один охранник в качестве подвыражения,

let my_fun a b = match a,b with
  | ((a,b) | (b,a)) when is_valid b -> process b

Вы увидите это в качестве примера в определении для шаблонов . Это действительно один шаблон, состоящий из шаблонов, которые сопоставляются.

4 голосов
/ 10 мая 2011

Что касается вашего первого вопроса, вы должны понять, что у вас есть только один шаблон ((a,b) | (b,a)), который является шаблоном "или".Сопоставление происходит слева направо по шаблону «или».Поскольку (a,b) будет соответствовать чему-либо, вторая часть никогда не будет использоваться.

По второму вопросу я не вижу проблемы, но это зависит от типов a и b.Вот пример:

type t = A of int | B of float

let my_fun a b = match a,b with
  | A a, B b
  | B b, A a when b > 0. ->  (float_of_int a) +. b
  | … -> (* other cases *)

Это также будет работать для более простых типов:

let my_fun a b = match a,b with
  | 1,b
  | b,1 when b > 0 -> b + 1
  | … -> (* other cases *)

Если вы все еще не можете заставить это работать в вашем случае, сообщите нам типыa и b с которыми вы работаете.

...