Учебник по Haskell | страница 66



| затем выражение-предикат, которое возвращает значение типа Bool, затем равно и после равно – возвра-

щаемое значение. Альтернативы так же как и в случае декомпозиции аргументов функции обходятся сверху

вниз, до тех пор пока в одной из альтернатив предикат не вернёт значение True. Обратите внимание на то,

что нам не нужно писать во второй альтернативе:

| 10 <= n && n < 30

= Enough

Если вычислитель дошёл до этой альтернативы, значит значение точно больше либо равно 10. Поскольку

в предыдущей альтернативе предикат вернул False.

Предикат в последней альтернативе является константой True, он пройдёт сопоставление с любым зна-

чением n. В данном случае, если учесть предыдущие альтернативы мы знаем, что если вычислитель дошёл

до последней альтернативы , значение n больше либо равно 30. Для повышения наглядности кода в Prelude

определена специальная константа-синоним значению True под именем otherwise.

Определим функцию filter для списков в более декларативном стиле, для этого заменим if-выражение

в исходной версии на охранные выражения:

filter :: (a -> Bool) -> [a] -> [a]

filter

p

[]

= []

filter

p

(x:xs)

| p x

= x : rest

| otherwise

= rest

where rest = filter p xs

Или мы можем разместить охранные выражения по-другому:

filter :: (a -> Bool) -> [a] -> [a]

filter

p

[]

= []

filter

p

(x:xs)

| p x

= x : rest

| otherwise = rest

where rest = 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)

where notP x = not (p x)

Или даже так:

import Prelude(all)

Функция null определена в Prelude она возвращает True только если список пуст.

if-выражения

В композиционном стиле в качестве условных выражений используются уже знакомые нам if-выражения.

Вспомним как они выглядят:

a = if bool

then x1

else