Исчерпывающность и сторожевые условия when
Используем способность компилятора проверять полноту разбора и уточняем образцы дополнительными условиями.
Проверка исчерпывающности — анализ компилятора, который предупреждает, если в
matchне покрыты все возможные формы значения.
Одно из самых ценных свойств OCaml: компилятор знает все возможные варианты вашего типа и проверяет, что вы их все обработали. Если добавить в тип новый конструктор, компилятор укажет каждое место, где про него забыли. Это превращает рефакторинг из источника багов в управляемый процесс.
Предупреждение о неполноте
type signal = Red | Yellow | Green
(* забыли Yellow *)
let action = function
| Red -> "стой"
| Green -> "иди"
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
Yellow
Компилятор приводит конкретный пример непокрытого случая. Игнорировать опасно: при попадании Yellow в рантайме программа бросит Match_failure.
Сторожевые условия when
let categorize n =
match n with
| 0 -> "ноль"
| n when n < 0 -> "отрицательное"
| n when n > 100 -> "большое"
| _ -> "обычное"
Ветка с when срабатывает, только если образец подошёл и условие истинно. Важно: компилятор не учитывает when при проверке исчерпывающности — поэтому после веток с when почти всегда нужен запасной _.
Объединение образцов через |
let is_vowel c =
match c with
| 'a' | 'e' | 'i' | 'o' | 'u' -> true
| _ -> false
Образцы, объединённые через |, должны связывать одни и те же переменные (или никаких).
Связывание целого через as
let dedup_head = function
| (x :: _) as lst when x = 0 -> lst
| lst -> lst
Как работает под капотом
Анализ исчерпывающности построен на том, что вариантные типы закрыты: компилятор знает полный список конструкторов. Для целых и строк исчерпывающим считается только наличие _ или переменной. Сторожевое условие when компилятор намеренно исключает из анализа: разрешимость произвольного булева выражения неразрешима в общем случае, поэтому язык консервативно требует запасной ветки.
Частые ошибки
- Игнорировать Warning 8. Неполный
match— потенциальныйMatch_failure. Многие проекты включают «warnings as errors». - Ждать, что
whenучтётся в исчерпывающности. Не учтётся; добавляйте запасной_. - Разные переменные в ветвях
|. Объединённые образцы должны связывать одинаковый набор имён.
Итоги
- Компилятор проверяет исчерпывающность и показывает пример непокрытого случая.
whenдобавляет условие к образцу, но не учитывается в проверке полноты.|объединяет образцы с общим результатом;asименует сопоставленный фрагмент целиком.