Читаем Учебник по Haskell полностью

*Kleisli> pred *$ pred *$ idK Zero

Nothing

Применение функций | 93

Обратите внимание на то как мы погружаем в мир специальных функций обычное значение с помощью

функции idK.

Вычислим третье поколение L-системы:

*Kleisli> next *$ next *$ next *$ idK ’a’

”abaab”

Мы можем использовать и другие функции на списках:

*Kleisli> next *$ tail $ next *$ reverse $ next *$ idK ’a’

”aba”

Применение функций многих переменных

С помощью функции +$ мы можем применять к специальным значениям обычные функции одного аргу-

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

Например если мы захотим сложить два частично определённых числа:

?? (+) (Just 2) (Just 2)

На месте ?? должна стоять функция типа:

?? :: (a -> b -> c) -> m a -> m b -> m c

Оказывается с помощью методов класса Kleisli мы можем определить такую функцию для любой обыч-

ной функции, а не только для функции двух аргументов. Мы будем называть такие функции словом liftN,

где N – число, указывающее на арность функции. Функция (liftN f) “поднимает” (от англ. lift) обычную

функцию f в мир специальных функций.

Функция lift1 у нас уже есть, это просто функция +$. Теперь давайте определим функцию lift2:

lift2 :: Kleisli m => (a -> b -> c) -> m a -> m b -> m c

lift2 f a b = ...

Поскольку функция двух аргументов на самом деле является функцией одного аргумента мы можем

применить первый аргумент с помощью функции lift1, посмотрим что у нас получится:

lift1

:: (a’ -> b’) -> m’ a’ -> m’ b’

f

:: (a -> b -> c)

a

:: m a

lift1 f a

:: m (b -> c)

-- m’ == m, a’ == a, b’ == b -> c

Теперь в нашем определении для lift2 появится новое слагаемое g:

lift2 :: Kleisli m => (a -> b -> c) -> m a -> m b -> m c

lift2 f a b = ...

where g = lift1 f a

Один аргумент мы применили, осталось применить второй. Нам нужно составить выражение (g b), но

для этого нам нужна функция типа:

m (b -> c) -> m b -> m c

Эта функция применяет к специальному значению функцию, которая завёрнута в тип m. Посмотрим на

определение этой функции, мы назовём её $$:

($$) :: Kleisli m => m (a -> b) -> m a -> m b

mf $$ ma = ( +$ ma) *$ mf

Вы можете убедиться в том, что это определение проходит проверку типов. Посмотрим как эта функция

работает в интерпретаторе на примере частично определённых и многозначных функций, для этого давайте

добавим в модуль Kleisli это определение и загрузим его в интерпретатор:

94 | Глава 6: Функторы и монады: теория

*Kleisli> :reload Kleisli

Ok, modules loaded: Kleisli, Nat.

*Kleisli> Just (+2) $$ Just 2

Just 4

*Kleisli> Nothing $$ Just 2

Nothing

*Kleisli> [(+1), (+2), (+3)] $$ [10,20,30]

[11,21,31,12,22,32,13,23,33]

*Kleisli> [(+1), (+2), (+3)] $$ []

[]

Обратите внимание на то, что в случае списков были составлены все возможные комбинации применений.

Мы применили первую функцию из списка ко всем аргументам, потом вторую функцию, третью и объединили

все результаты в список.

Теперь мы можем закончить наше определение для lift2:

lift2 :: Kleisli m => (a -> b -> c) -> m a -> m b -> m c

lift2 f a b = f’ $$ b

where f’ = lift1 f a

Мы можем записать это определение более кратко:

lift2 :: Kleisli m => (a -> b -> c) -> m a -> m b -> m c

lift2 f a b = lift1 f a $$ b

Теперь давайте добавим это определение в модуль Kleisli и посмотрим в интерпретаторе как работает

эта функция:

*Kleisli> :reload

[2 of 2] Compiling Kleisli

( Kleisli. hs, interpreted )

Ok, modules loaded: Kleisli, Nat.

*Kleisli> lift2 (+) (Just 2) (Just 2)

Just 4

*Kleisli> lift2 (+) (Just 2) Nothing

Nothing

Как на счёт функций трёх и более аргументов? У нас уже есть функции lift1 и lift2 определим функцию

lift3:

lift3 :: Kleisli m => (a -> b -> c -> d) -> m a -> m b -> m c -> m d lift3 f a b c = ...

Первые два аргумента мы можем применить с помощью функции lift2. Посмотрим на тип получивше-

гося выражения:

lift2

:: Kleisli m => (a’ -> b’ -> c’) -> m a’ -> m b’ -> m c’

f

:: a -> b -> c -> d

lift2 f a b :: m (c -> d)

-- a’ == a, b’ == b, c’ == c -> d

У нас опять появился тип m (c -> d) и к нему нам нужно применить значение m c, чтобы получить m d.

Этим как раз и занимается функция $$. Итак итоговое определение примет вид:

lift3 :: Kleisli m => (a -> b -> c -> d) -> m a -> m b -> m c -> m d lift3 f a b c = lift2 f a b $$ c

Так мы можем определить любую функцию liftN через функции liftN-1 и $$.

Несколько полезных функций

Теперь мы умеем применять к специальным значениям произвольные обычные функции. Определим ещё

несколько полезных функций. Первая функция принимает список специальных значений и собирает их в

специальный список:

Применение функций | 95

import Prelude hiding (id, (>> ), pred, sequence)

sequence :: Kleisli m => [m a] -> m [a]

sequence = foldr (lift2 (:)) (idK [])

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных