52700.fb2 Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 68

Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 68

snd :: (a, b) -> b

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