.
Если в образце вместо реального значения (например, >7
) пишут идентификатор, начинающийся со строчной буквы (например, >x
, >y
или >myNumber
), то этот образец будет сопоставлен любому переданному значению. Обратиться к сопоставленному значению в теле функции можно будет посредством введённого идентификатора.
Эта функция может быть реализована с использованием ключевого слова >if
. Ну а если нам потребуется написать функцию, которая называет цифры от 1 до 5 и выводит >"Это число не в пределах от 1 до 5"
для других чисел? Без сопоставления с образцом нам бы пришлось создать очень запутанное дерево условных выражений >if
– >then
– >else
. А вот что получится, если использовать сопоставление:
>sayMe :: Int -> String
>sayMe 1 = "Один!"
>sayMe 2 = "Два!"
>sayMe 3 = "Три!"
>sayMe 4 = "Четыре!"
>sayMe 5 = "Пять!"
>sayMe x = "Это число не в пределах от 1 до 5"
Заметьте, что если бы мы переместили последнюю строку определения функции (образец в которой соответствует любому вводу) вверх, то функция всегда выводила бы >"Это число не в пределах от 1 до 5"
, потому что невозможно было бы пройти дальше и провести проверку на совпадение с другими образцами.
Помните реализованную нами функцию факториала? Мы определили факториал числа >n
как произведение чисел >[1..n]
. Мы можем определить данную функцию рекурсивно, точно так же, как факториал определяется в математике. Начнём с того, что объявим факториал нуля равным единице.
Затем определим факториал любого положительного числа как данное число, умноженное на факториал предыдущего числа. Вот как это будет выглядеть в терминах языка Haskell.
>factorial :: Integer -> Integer
>factorial 0 = 1
>factorial n = n * factorial (n – 1)
Мы в первый раз задали функцию рекурсивно. Рекурсия очень важна в языке Haskell, и подробнее она будет рассмотрена позже.
Сопоставление с образцом может завершиться неудачей, если мы зададим функцию следующим образом:
>charName :: Char –> String
>charName 'а' = "Артём"
>charName 'б' = "Борис"
>charName 'в' = "Виктор"
а затем попытаемся вызвать её с параметром, которого не ожидали. Произойдёт следующее:
>ghci> charName 'а'
>"Артём"
>ghci> charName 'в'
>"Виктор"
>ghci> charName 'м'
>"*** Exception: Non-exhaustive patterns in function charName
Это жалоба на то, что наши образцы не покрывают всех возможных случаев (недоопределены) – и, воистину, так оно и есть! Когда мы определяем функцию, мы должны всегда включать образец, который можно сопоставить с любым входным значением, для того чтобы наша программа не закрывалась с сообщением об ошибке, если функция получит какие-то непредвиденные входные данные.