wheresucc x =x +1
Но иногда это бывает полезно, при использовании классов типов, для избежания неопределённости при-
менения.
Приведём ещё один пример. Посмотрим на функцию фильтрации списков, она определена в Prelude:
filter ::(a -> Bool) ->[a] ->[a]
filter
p
[]
= []
filter
p
(x :xs) = ifp x thenx :rest elserest
whererest =filter p xs
Мы определили локальную переменную rest, которая указывает на рекурсивный вызов функции на остав-
шейся части списка.
where-выражения определяются для каждого уравнения в определении функции:
even :: Nat -> Bool
even Zero
=res
whereres = True
even ( Succ Zero) =res
whereres = False
even x =even res
where( Succ( Succres)) =x
Конечно в этом примере whereне нужны, но здесь они приведены для иллюстрации привязки where-
выражения к данному уравнению. Мы определили три локальных переменных с одним и тем же именем.
where-выражения могут быть и у значений, которые определяются внутри where-выражений. Но лучше
избегать сильно вложенных выражений.
60 | Глава 4: Декларативный и композиционный стиль
let-выражения
В композиционном стиле функция вычисления площади треугольника будет выглядеть так:
square a b c = letp =(a +b +c) /2
in
sqrt (p *(p -a) *(p -b) *(p -c))
Слова letи in– ключевые. Выгодным отличием let-выражений является то, что они являются обычными
выражениями и не привязаны к определённому месту как where-выражения. Они могут участвовать в любой
части обычного выражения:
square a b c = letp =(a +b +c) /2
in
sqrt (( letpa =p -a inp *pa) *
( letpb =p -b
pc =p -c
in
pb *pc))
В этом проявляется их принадлежность композиционному стилю. let-выражения могут участвовать в
любом подвыражении, они также группируются скобками. А where-выражения привязаны к уравнениям в
определении функции.
Также как и в where-выражениях, в let-выражениях слева от знака равно можно проводить декомпозицию
значений.
pred :: Nat -> Nat
pred x = let( Succy) =x
in
y
Определим функцию фильтрации списков через let:
filter ::(a -> Bool) ->[a] ->[a]
filter
p
[]
= []
filter
p
(x :xs) =
letrest =filter p xs
in
ifp x thenx :rest elserest
4.2 Декомпозиция
Декомпозиция или сопоставление с образцом позволяет выделять из составных значений, простейшие
значения с помощью которых они были построены
pred ( Succx) =x
и организовывать условные вычисления которые зависят от вида поступающих на вход функции значений
not True
= False
not False = True
Сопоставление с образцом
Декомпозицию в декларативном стиле мы уже изучили, это обычный случай разбора значений в аргу-
ментах функции. Рассмотрим одну полезную возможность при декомпозиции. Иногда нам хочется провести
декомпозицию и дать псевдоним всему значению. Это можно сделать с помощью специального символа @.
Например определим функцию, которая возвращает соседние числа для данного числа Пеано:
beside :: Nat ->( Nat, Nat)
beside
Zero
= error”undefined”
beside
x @( Succy) =(y, Succx)
В выражении x“(Succ y)@ мы одновременно проводим разбор и даём имя всему значению.
Декомпозиция | 61
case-выражения
Оказывается декомпозицию можно проводить в любом выражении, для этого существуют case-
выражения:
data AnotherNat = None | One | Two | Many
deriving( Show, Eq)
toAnother :: Nat -> AnotherNat
toAnother x =
casex of
Zero
-> None
Succ Zero
-> One
Succ( Succ Zero)
-> Two
_
-> Many
Читать дальше