Читаем Изучай Haskell во имя добра! полностью

Легко увидеть, что вызов выражения pure f <*> xs при использовании списков эквивалентен выражению fmap f xs. Результат вычисления pure f – это просто [f], а выражение [f] <*> xs применит каждую функцию в левом списке к каждому значению в правом; но в левом списке только одна функция, и, следовательно, это похоже на отображение.

<p>Тип IO – тоже аппликативный функтор</p>

Другой экземпляр класса Applicative, с которым мы уже встречались, – экземпляр для типа IO. Вот как он реализован:

instance Applicative IO where

   pure = return

   a <*> b = do

      f <– a

      x <– b

      return (f x)

Поскольку суть функции pure состоит в помещении значения в минимальный контекст, который всё ещё содержит значение как результат, логично, что в случае с типом IO функция pure – это просто вызов return. Функция return создаёт действие ввода-вывода, которое ничего не делает. Оно просто возвращает некое значение в качестве своего результата, не производя никаких операций ввода-вывода вроде печати на терминал или чтения из файла.

Если бы оператор <*> ограничивался работой с типом IO, он бы имел тип (<*>) :: IO (a –> b) –> IO a –> IO b. В случае с типом IO он принимает действие ввода-вывода a, которое возвращает функцию, выполняет действие ввода-вывода и связывает эту функцию с идентификатором f. Затем он выполняет действие ввода-вывода b и связывает его результат с идентификатором x. Наконец, он применяет функцию f к значению x и возвращает результат этого применения в качестве результата. Чтобы это реализовать, мы использовали здесь синтаксис do. (Вспомните, что суть синтаксиса do заключается в том, чтобы взять несколько действий ввода-вывода и «склеить» их в одно.)

При использовании типов Maybe и [] мы могли бы воспринимать применение функции <*> просто как извлечение функции из её левого параметра, а затем применение её к правому параметру. В отношении типа IO извлечение остаётся в силе, но теперь у нас появляется понятие помещения в последовательность, поскольку мы берём два действия ввода-вывода и «склеиваем» их в одно. Мы должны извлечь функцию из первого действия ввода-вывода, но для того, чтобы можно было извлечь результат из действия ввода-вывода, последнее должно быть выполнено. Рассмотрите вот это:

myAction :: IO String

myAction = do

   a <– getLine

   b <– getLine

   return $ a ++ b

Это действие ввода-вывода, которое запросит у пользователя две строки и вернёт в качестве своего результата их конкатенацию. Мы достигли этого благодаря «склеиванию» двух действий ввода-вывода getLine и return, поскольку мы хотели, чтобы наше новое «склеенное» действие ввода-вывода содержало результат выполнения a ++ b. Ещё один способ записать это состоит в использовании аппликативного стиля:

myAction :: IO String

myAction = (++) <$> getLine <*> getLine

Это то же, что мы делали ранее, когда создавали действие ввода-вывода, которое применяло функцию между результатами двух других действий ввода-вывода. Вспомните, что функция getLine – это действие ввода-вывода, которое имеет тип getLine :: IO String. Когда мы применяем оператор <*> между двумя аппликативными значениями, результатом является аппликативное значение, так что всё это имеет смысл.

Если мы вернёмся к аналогии с коробками, то можем представить себе функцию getLine как коробку, которая выйдет в реальный мир и принесёт нам строку. Выполнение выражения (++) <$> getLine <*> getLine создаёт другую, бо́льшую коробку, которая посылает эти две коробки наружу для получения строк с терминала, а потом возвращает конкатенацию этих двух строк в качестве своего результата.

Выражение (++) <$> getLine <*> getLine имеет тип IO String. Это означает, что данное выражение является совершенно обычным действием ввода-вывода, как и любое другое, тоже возвращая результирующее значение, подобно другим действиям ввода-вывода. Вот почему мы можем выполнять следующие вещи:

main = do

   a <– (++) <$> getLine <*> getLine

   putStrLn $ "Две строки, соединённые вместе: " ++ a

<p>Функции в качестве аппликативных функторов</p>

Ещё одним экземпляром класса Applicative является тип (–>) r, или функции. Мы нечасто используем функции в аппликативном стиле, но концепция, тем не менее, действительно интересна, поэтому давайте взглянем, как реализован экземпляр функции[12].

instance Applicative ((–>) r) where

   pure x = (\_ –> x)

   f <*> g = \x –> f x (g x)

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

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

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

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

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

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

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

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

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