Изучай Haskell во имя добра! (Липовача) - страница 29

.

Если в образце вместо реального значения (например, >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

Это жалоба на то, что наши образцы не покрывают всех возможных случаев (недоопределены) – и, воистину, так оно и есть! Когда мы определяем функцию, мы должны всегда включать образец, который можно сопоставить с любым входным значением, для того чтобы наша программа не закрывалась с сообщением об ошибке, если функция получит какие-то непредвиденные входные данные.