до последней альтернативы , значение n больше либо равно 30. Для повышения наглядности кода в Prelude
определена специальная константа-синоним значению Trueпод именем otherwise.
Определим функцию filter для списков в более декларативном стиле, для этого заменим if-выражение
в исходной версии на охранные выражения:
filter ::(a -> Bool) ->[a] ->[a]
filter
p
[]
= []
filter
p
(x :xs)
|p x
=x :rest
|otherwise
=rest
whererest =filter p xs
Или мы можем разместить охранные выражения по-другому:
filter ::(a -> Bool) ->[a] ->[a]
filter
p
[]
= []
filter
p
(x :xs)
|p x
=x :rest
|otherwise =rest
whererest =filter p xs
Отметим то, что локальная переменная rest видна и в той и в другой альтернативе. Вы спокойно можете
пользоваться локальными переменными в любой части уравнения, в котором они определены.
Определим с помощью охранных выражений функцию all, она принимает предикат и список, и проверяет
удовлетворяют ли все элементы списка данному предикату.
all ::(a -> Bool) ->[a] -> Bool
all p []
= True
all p (x :xs)
|p x
=all p xs
|otherwise = False
С помощью охранных выражений можно очень наглядно описывать условные выражения. Но иногда мож-
но обойтись и простыми логическими операциями. Например функцию all можно было бы определить так:
Условные выражения | 63
all ::(a -> Bool) ->[a] -> Bool
all
p
[]
= True
all
p
(x :xs)
=p x &&all p xs
Или так:
all ::(a -> Bool) ->[a] -> Bool
all
p
xs =null (filter notP xs)
wherenotP x =not (p x)
Или даже так:
import Prelude(all)
Функция null определена в Preludeона возвращает Trueтолько если список пуст.
if-выражения
В композиционном стиле в качестве условных выражений используются уже знакомые нам if-выражения.
Вспомним как они выглядят:
a = ifbool
thenx1
elsex2
Слова if, thenи else– ключевые. Тип a, x1 и x2 совпадают.
Любое охранное выражение, в котором больше одной альтернативы, можно представить в виде if-
выражения и наоборот. Перепишем все функции их предыдущего подраздела с помощью if-выражений:
hallCapacity :: Int -> HowMany
hallCapacity n =
if(n <10)
then Little
else( ifn <30
then Enough
else Many)
all ::(a -> Bool) ->[a] -> Bool
all p []
= True
all p (x :xs) = if(p x) thenall p xs else False
4.4 Определение функций
Под функцией мы понимаем составной синоним, который принимает аргументы, возможно разбирает их
на части и составляет из этих частей новые выражения. Теперь посмотрим как такие синонимы определяются
в каждом из стилей.
Уравнения
В декларативном стиле функции определяются с помощью уравнений. Пока мы видели лишь этот способ
определения функций, примерами могут служить все предыдущие примеры. Вкратце напомним, что функция
определяется набором уравнений вида:
name декомпозиция1 = композиция1
name декомпозиция2 = композиция2
...
name декомпозицияN = композицияN
Где name – имя функции. В декомпозициипроисходит разбор поступающих на вход значений, а в компо-
зициипроисходит составление значения результата. Уравнения обходятся вычислителем сверху вниз до тех
пор пока он не найдёт такое уравнение, для которого переданные в функции значения не подойдут в указан-
ный в декомпозиции шаблон значений (если сопоставление с образцом аргументов пройдёт успешно). Как
только такое уравнение найдено, составляется выражение справа от знака равно ( композиция). Это значение
будет результатом функции. Если такое уравнение не будет найдено программа остановится с ошибкой.
К примеру попробуйте вычислить в интерпретаторе выражение notT False, для такой функции:
Читать дальше