match: основы сопоставления с образцом
Осваиваем сердце OCaml — конструкцию match, которая одновременно разбирает структуру данных и извлекает из неё значения.
Сопоставление с образцом (pattern matching) — выбор ветки по форме значения с одновременным извлечением его частей в переменные.
Если в императивных языках разбор данных — это череда if/switch и ручное извлечение полей, то в OCaml это одна выразительная конструкция. match сравнивает значение с набором образцов и для подошедшего выполняет ветку, попутно связывая части значения с именами.
Базовый синтаксис
let describe n =
match n with
| 0 -> "ноль"
| 1 -> "один"
| _ -> "много"
Каждая ветка начинается с |, затем образец, стрелка -> и результат. Образец _ — «что угодно». Все ветки возвращают значения одного типа, ведь match — выражение.
Связывание переменных
type shape = Circle of float | Rect of float * float
let area s =
match s with
| Circle r -> 3.14159 *. r *. r
| Rect (w, h) -> w *. h
В ветке Circle r имя r связывается с радиусом, в Rect (w, h) — w и h с шириной и высотой. Образец делает извлечение сам.
Разбор кортежей и вложенность
let classify pair =
match pair with
| (0, 0) -> "начало координат"
| (0, _) -> "на оси Y"
| (_, 0) -> "на оси X"
| (x, y) -> Printf.sprintf "точка (%d, %d)" x y
Образцы проверяются сверху вниз: первый подошедший выигрывает. Поэтому конкретные случаи ставят выше общих.
Сокращение function
let area = function
| Circle r -> 3.14159 *. r *. r
| Rect (w, h) -> w *. h
Это эквивалентно fun s -> match s with ..., просто короче.
Как работает под капотом
Компилятор не выполняет образцы наивно «по одному». Он строит дерево решений — оптимальную последовательность проверок, которая разбирает значение за минимальное число шагов, заглядывая в теги конструкторов. Кроме того, анализатор образцов проверяет два свойства: исчерпывающность (покрыты ли все случаи) и избыточность (нет ли недостижимых веток). Оба выдаются как предупреждения — бесплатная проверка логики.
Частые ошибки
- Поставить общий образец
_слишком рано. Он поглотит последующие ветки. - Думать, что переменная в образце сравнивается со значением. Имя
xсвязывается с любым значением, а не проверяет равенство. - Забыть
|перед веткой. Первый|можно опустить, но единообразие читается лучше.
Итоги
match значение with | образец -> ...выбирает ветку по форме данных и связывает их части.- Образцы проверяются сверху вниз;
_ловит всё остальное и должен идти последним. function— краткая запись функции, сразу делающейmatchпо аргументу.