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

Мы “спрячем” из Prelude одноимённую функцию sequence. Посмотрим на примеры:

*Kleisli> sequence [Just 1, Just 2, Just 3]

Just [1,2,3]

*Kleisli> sequence [Just 1, Nothing, Just 3]

Nothing

Во второй команде вся функция вернула Nothing потому что при объединении списка встретилось зна-

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

которые могут не вычислить результат. Поскольку значение одного из элементов не определено, весь список

не определён.

Посмотрим как работает эта функция на списках:

*Kleisli> sequence [[1,2,3], [11,22]]

[[1,11],[1,22],[2,11],[2,22],[3,11],[3,22]]

Она составляет список всех комбинаций элементов из всех подсписков.

С помощью этой функции мы можем определить функцию mapK. Эта функция является аналогом обычной

функции map, но она применяет специальную функцию к списку значений.

mapK :: Kleisli m => (a -> m b) -> [a] -> m [b]

mapK f = sequence . map f

6.4 Функторы и монады

В этой главе мы выписали вручную все определения для класса Kleisli. Мы сделали это потому, что на

самом деле в арсенале стандартных средств Haskell такого класса нет. Класс Kleisli строит замкнутый мир

специальных функций a -> m b. Его цель построить язык в языке и сделать программирование со специ-

альными функциями таким же удобным как и с обычными функциями. Мы пользовались классом Kleisli

исключительно в целях облегчения понимания этого мира. Впрочем никто не мешает нам определить этот

класс и пользоваться им в наших программах.

А пока посмотрим, что есть в Haskell и как это соотносится с тем, что мы уже увидели. С помощью класса

Kleisli

мы научились делать три различных операции применения:

Применение:

• обычных функций одного аргумента к специальным значениям (функция +$).

• обычных функций произвольного числа аргументов к специальным значениям (функции +$ и $$)

• специальных функций к специальным значениям (функция *$).

В Haskell для решения этих задач предназначены три отдельных класса. Это функторы, аппликативные

функторы и монады.

Функторы

Посмотрим на определение класса Functor:

class Functor f where

fmap :: (a -> b) -> f a -> f b

Тип метода fmap совпадает с типом для функции +$:

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

Нам только нужно заменить m на f и зависимость от Kleisli на зависимость от Functor:

Итак в Haskell у нас есть базовая операция fmap применения обычной функции к значению из мира спе-

циальных функций. В модуле Control.Applicative определён инфиксный синоним <$> для этой функции.

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

Аппликативные функторы

Посмотрим на определение класса Applicative:

class Functor f => Applicative f where

pure

:: a -> f a

(<*> )

:: f (a -> b) -> f a -> f b

Если присмотреться к типам методов этого класса, то мы заметим, что это наши старые знакомые idK и

$$. Если для данного типа f определён экземпляр класса Applicative, то из контекста следует, что для него

также определён и экземпляр класса Functor.

Значит у нас есть функции fmap (или lift1) и <*> (или $$). С их помощью мы можем составить функции

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

Класс Applicative определён в модуле Control.Applicative, там же мы сможем найти и функции liftA,

liftA2, liftA3 и символьный синоним <$> для функции fmap. Функции liftAn определены так:

liftA2 f a b

= f <$> a <*> b

liftA3 f a b c = f <$> a <*> b <*> c

Видно что эти определения с точностью до обозначений совпадают с теми, что мы уже писали для класса

Kleisli.

Монады

Посмотрим на определение класса Monad

class Monad m where

return :: a -> m a

(>>=)

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

Присмотримся к типам методов этого класса:

return :: a -> m a

Их типа видно, что это ни что иное как функция idK. В классе Monad у неё точно такой же смысл. Теперь

функция >>=, она читается как функция связывания (bind).

(>>=)

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

Так возможно совпадение не заметно, но давайте “перевернём” эту функцию:

(=<< )

:: Monad m => (a -> m b) -> m a -> m b

(=<< ) = flip (>>=)

Поменяв аргументы местами, мы получили знакомую функцию *$. Итак функция связывания это функция

применения специальной функции к специальному значению. У неё как раз такой смысл.

В Prelude определены экземпляры класса Monad для типов Maybe и [].

Они определены по такому же принципу, что и наши определения для Kleisli только не для композиции, а

для применения.

Отметим, что в модуле Control.Monad определены функции sequence и mapM, они несут тот же смысл,

что и функции sequence и mapК, которые мы определяли для класса Kleisli.

Свойства классов

Посмотрим на свойства функторов и аппликативных функторов.

Функторы и монады | 97

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

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

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

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

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

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

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

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

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