Выражения для выбора из вариантов

Во многих императивных языках (C, C++, Java, и т. д.) имеется оператор case, и если вам доводилось программировать на них, вы знаете, что это такое. Вы берёте переменную и выполняете некую часть кода для каждого значения этой переменной – ну и, возможно, используете финальное условие, которое срабатывает, если не отработали другие.

Язык Haskell позаимствовал эту концепцию и усовершенствовал её. Само имя «выражения для выбора» указывает на то, что они являются… э-э-э… выражениями, так же как if – then – else и let. Мы не только можем вычислять выражения, основываясь на возможных значениях переменной, но и производить сопоставление с образцом.

Итак, берём переменную, выполняем сопоставление с образцом, выполняем участок кода в зависимости от полученного значения… где-то мы это уже слышали!.. Ах да, сопоставление с образцом по параметрам при объявлении функции! На самом деле это всего лишь навсего облегчённая запись для выражений выбора. Эти два фрагмента кода делают одно и то же – они взаимозаменяемы:

head' :: [a] –> a

head' [] = error "Никаких head для пустых списков!"

head' (x:_) = x

head' :: [a] –> a

head' xs =

  case xs of

   [] –> error "Никаких head для пустых списков!"

   (x:_) –> x

Как видите, синтаксис для выражений отбора довольно прост:

case expression of

  pattern –> result

  pattern –> result

  ...

Выражения проверяются на соответствие образцам. Сопоставление с образцом работает как обычно: используется первый образец, который подошёл. Если были опробованы все образцы и ни один не подошёл, генерируется ошибка времени выполнения.

Сопоставление с образцом по параметрам функции может быть сделано только при объявлении функции; выражения отбора могут использоваться практически везде. Например:

describeList :: [a] –> String

describeList xs = "Список " ++

  case xs of

   [] –> "пуст."

   [x] –> "одноэлементный."

   xs –> "длинный."

Они удобны для сопоставления с каким-нибудь образцом в середине выражения. Поскольку сопоставление с образцом при объявлении функции – это всего лишь упрощённая запись выражений отбора, мы могли бы определить функцию таким образом:

describeList :: [a] –> String

describeList xs = "Список " ++ what xs

  where

    what [] = "пуст."

    what [x] = "одноэлементный."

    what xs = "длинный."