Когда вы делаете:
| a :: b :: t -> ...
Вы не обязательно сопоставляете два элемента в списке. Лучше использовать []
вместо t
для точного соответствия двух элементов - t
может быть списком других элементов.
| a :: b :: [] -> Two (a+b)
Это гарантирует, что вы сопоставляете два и только два элемента - проверка ошибок бесплатно! Я предлагаю сделать это, даже если вы ожидаете, что функция будет принимать только список из 0, 1 или 2 элементов. Таким образом,
EDIT:
let (|MatchTwo|_|) = function
| a :: b :: t -> Some(a + b :: t)
| _ -> None
let (|Nil|One|Two|) (l : int list) = match l with
| MatchTwo(IsValid(a) :: t) -> Two(a)
| IsValid(a) :: t -> One(a)
| _ -> Nil
Да, используйте when
. Это беспорядок. Сопоставление с образцом заключается в том, что применение функций в сопоставлении действительно не имеет смысла. Но примите во внимание то, что я упомянул ранее. На основании вашего примера:
match l with
| a :: b :: t when isValid (a+b) -> Two (a+b)
| a :: t when isValid (a) -> One a
| _ -> Nil
Второй шаблон будет соответствовать спискам длиной больше единицы, если isValid имеет значение false в первом шаблоне - будьте предупреждены. Будьте максимально конкретны в своих шаблонах, если вы хотите соответствовать одному элементу, сделайте это.
Если какая-либо операция, которую вы используете для объединения a и b (в данном случае +), является вычислительно дорогой, вам придется отбросить when
и использовать оператор let перед проверкой isValid и возвращением типа варианта.