fromAnother :: AnotherNat -> Nat
fromAnother None
= Zero
fromAnother One
= Succ Zero
fromAnother Two
= Succ( Succ Zero)
fromAnother Many
= error”undefined”
Слова caseи of– ключевые. Выгодным отличием case-выражений является то, что нам не приходит-
ся каждый раз выписывать имя функции. Обратите внимание на то, что в case-выражениях также можно
пользоваться обычными переменными и безымянными переменными.
Для проведения декомпозиции по нескольким переменным можно воспользоваться кортежами. Например
определим знакомую функцию равенства для Nat:
instance Eq Nat where
( ==) a b =
case(a, b) of
( Zero,
Zero)
-> True
( Succa’, Succb’)
->a’ ==b’
_
-> False
Мы проводим сопоставление с образцом по кортежу (a, b), соответственно слева от знака ->мы прове-
ряем значения в кортежах, для этого мы также заключаем значения в скобки и пишем их через запятую.
Давайте определим функцию filter в ещё более композиционном стиле. Для этого мы заменим в исход-
ном определении whereна letи декомпозицию в аргументах на case-выражение:
filter ::(a -> Bool) ->[a] ->[a]
filter
p
a =
casea of
[]
-> []
x :xs
->
letrest =filter p xs
in
if(p x)
then(x :rest)
elserest
4.3 Условные выражения
С условными выражениями мы уже сталкивались в сопоставлении с образцом. Например в определении
функции not:
not True
= False
not False = True
В зависимости от поступающего значения мы выбираем одну из двух альтернатив. Условные выражении
в сопоставлении с образцом позволяют реагировать лишь на частичное (с учётом переменных) совпадение
дерева значения в аргументах функции.
Часто нам хочется определить более сложные условия для альтернатив. Например, если значение на
входе функции больше 2, но меньше 10, верни A, а если больше 10, верни B, а во всех остальных случаях
верни C. Или если на вход поступила строка состоящая только из букв латинского алфавита, верни A, а
в противном случае верни B. Нам бы хотелось реагировать лишь в том случае, если значение некоторого
типа a удовлетворяет некоторому предикату. Предикатами обычно называют функции типа a -> Bool. Мы
говорим, что значение удовлетворяет предикату, если предикат для этого значения возвращает True.
62 | Глава 4: Декларативный и композиционный стиль
Охранные выражения
В декларативном стиле условные выражения представлены охранными выражениями (guards). Предполо-
жим у нас есть тип:
data HowMany = Little | Enough | Many
И мы хотим написать функцию, которая принимает число людей, которые хотят посетить выставку, а
возвращает значение типа HowMany. Эта функция оценивает вместительность выставочного зала. С помощью
охранных выражений мы можем написать её так:
hallCapacity :: Int -> HowMany
hallCapacity n
|n <10
= Little
|n <30
= Enough
| True
= Many
Специальный символ |уже встречался нам в определении типов. Там он играл роль разделителя аль-
тернатив в сумме типов. Здесь же он разделяет альтернативы в условных выражениях. Сначала мы пишем
|затем выражение-предикат, которое возвращает значение типа Bool, затем равно и после равно – возвра-
щаемое значение. Альтернативы так же как и в случае декомпозиции аргументов функции обходятся сверху
вниз, до тех пор пока в одной из альтернатив предикат не вернёт значение True. Обратите внимание на то,
что нам не нужно писать во второй альтернативе:
|10 <=n &&n <30
= Enough
Если вычислитель дошёл до этой альтернативы, значит значение точно больше либо равно 10. Поскольку
в предыдущей альтернативе предикат вернул False.
Предикат в последней альтернативе является константой True, он пройдёт сопоставление с любым зна-
чением n. В данном случае, если учесть предыдущие альтернативы мы знаем, что если вычислитель дошёл
Читать дальше