52700.fb2
snd = \(_, b) -> b
swap :: (a, b) -> (b, a)
swap = \(a, b) -> (b, a)
Обратите внимание на то, что все функции словно являются константами. Они не содержат аргументов.
Аргументы мы “пристраиваем” с помощью безымянных функций.
Определим функции преобразования первого и второго элемента кортежа (эти функции определены в
модуле Control.Arrow)
first :: (a -> a’) -> (a, b) -> (a’, b)
first = \f (a, b) -> (f a, b)
second :: (b -> b’) -> (a, b) -> (a, b’)
second = \f (a, b) -> (a, f b)
Также в Prelude есть полезные функции, которые превращают функции с частичным применением в
обычны функции и наоборот:
curry :: ((a, b) -> c) -> a -> b -> c
curry = \f -> \a -> \b -> f (a, b)
uncurry :: (a -> b -> c) -> ((a, b) -> c)
uncurry = \f -> \(a, b) -> f a b
66 | Глава 4: Декларативный и композиционный стиль
Функция curry принимает функцию двух аргументов для которой частичное применение невозможно.
Это имитируется с помощью кортежей. Функция принимает кортеж из двух элементов. Функция curry (от
слова каррирование, частичное применение) превращает такую функцию в обычную функцию Haskell. А
функция uncurry выполняет обратное преобразование.
С помощью лямбда-функций можно имитировать локальные переменные. Так например можно перепи-
сать формулу для вычисления площади треугольника:
square a b c =
(\p -> sqrt (p * (p - a) * (p - b) * (p - c)))
((a + b + c) / 2)
Смотрите мы определили функцию, которая принимает параметром полупериметр p и передали в неё
значение ((a + b + c) / 2). Если в нашей функции несколько локальных переменных, то мы можем
составить лямбда-функцию от нескольких переменных и подставить в неё нужные значения.
4.5 Какой стиль лучше?
Основной критерий выбора заключается в том, сделает ли этот элемент код более ясным. Наглядность
кода станет залогом успешной поддержки. Его будет легче понять и улучшить при необходимости.
Далее мы рассмотрим несколько примеров определений из Prelude и подумаем, почему был выбран тот
или иной стиль. Начнём с класса Ord и посмотрим на определения по умолчанию:
-- Тип упорядочивания
data
Ordering
=
LT | EQ | GT
deriving (Eq, Ord, Enum, Read, Show, Bounded)
class
(Eq a) => Ord a
where
compare
:: a -> a -> Ordering
(< ), (<=), (>=), (> ) :: a -> a -> Bool
max, min
:: a -> a -> a