Сопоставление с образцом и конструкторы

Почему я получаю ошибки, когда пишу такой тип сопоставления:

type t = A of int | B of float

let f = function
        | (A i | B f) -> true
        | _ -> false

или же

let f = function
        | A i | B f -> true
        | _ -> false

Ошибка: переменная f должна встречаться по обе стороны от этого | шаблон

let f = function
        | (A i | B i) -> true
        | _ -> false

или же

let f = function
        | A i | B i -> true
        | _ -> false

Ошибка: этот шаблон соответствует значениям типа int типа float, но ожидался шаблон, соответствующий значению

2 ответа

Решение

Если вы предоставляете одну правую часть для нескольких шаблонов (как вы делаете), OCaml требует, чтобы шаблоны последовательно связывались с переменными шаблона.

В первой ситуации

match ... with
  | A i | B f -> ...
  ...

шаблоны не согласуются с переменными, с которыми они связаны: первый шаблон связан с iв то время как второй связывается с f,

Во второй ситуации

match ... with
  | A i | B i -> ...
  ...

шаблоны не согласовывают тип значений для привязки к своим переменным: первый шаблон связывает значение типа int в iв то время как второй связывает значение типа float в i,

Единственный способ, которым эти два шаблона могут последовательно связываться с переменными, это вообще не связывать с какими-либо переменными:

match ... with
  | A _ | B _ -> ...
  ...

Полный пример становится

type t = A of int | B of float

let f = function
  | A _ | B _ -> true
  | _ -> false

(Но учтите, что последняя ветвь сопоставления с образцом является излишней, так как первые две фигуры уже полностью соответствуют всем значениям вашего типа t, Отсюда получаем:

let f = function
  | A _ | B _ -> true

Это, конечно, эквивалентно написанию let f _ = true.)

В Or шаблон (| шаблон), вы теряете, в каких конструкторах вы находитесь. Следовательно, вам нужно привязать один и тот же набор переменных для работы, не обращаясь к конструкторам.

И OCaml строго типизирован; ценность i не может иметь оба типа int и введите float,

Если тип t имеет более двух случаев, вы должны написать:

let f = function
        | A _ | B _ -> true
        | _ -> false

иначе:

let f = function
        | A _ | B _ -> true

достаточно, поскольку сопоставление с образцом уже является исчерпывающим.

я согласна с тем что Or шаблон довольно ограничен, но иногда это полезно, когда у вас есть симметричные случаи в вашей функции:

type num = 
    | Int of int
    | Float of float

let add s1 s2 = 
    match s1, s2 with
    | Int i1, Int i2 -> Int (i1 + i2)
    | Int i, Float f | Float f, Int i -> Float (float i +. f)
    | Float f1, Float f2 -> Float (f1 +. f2)
Другие вопросы по тегам