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

Первые два закона утверждают, что значение mempty должно вести себя как единица по отношению к функции mappend, а третий говорит, что функция mappend должна быть ассоциативна (порядок, в котором мы используем функцию mappend для сведения нескольких моноидных значений в одно, не имеет значения). Язык Haskell не проверяет определяемые экземпляры на соответствие этим законам, поэтому мы должны быть внимательными, чтобы наши экземпляры действительно выполняли их.

<p>Познакомьтесь с некоторыми моноидами</p>

Теперь, когда вы знаете, что такое моноиды, давайте изучим некоторые типы в языке Haskell, которые являются моноидами, посмотрим, как выглядят экземпляры класса Monoid для них, и поговорим об их использовании.

<p>Списки являются моноидами</p>

Да, списки являются моноидами! Как вы уже видели, функция ++ с пустым списком [] образуют моноид. Экземпляр очень прост:

instance Monoid [a] where

   mempty = []

   mappend = (++)

Для списков имеется экземпляр класса Monoid независимо от типа элементов, которые они содержат. Обратите внимание, что мы написали instance Monoid [a], а не instance Monoid [], поскольку класс Monoid требует конкретный тип для экземпляра.

При тестировании мы не встречаем сюрпризов:

ghci> [1,2,3] `mappend` [4,5,6]

[1,2,3,4,5,6]

ghci> ("один" `mappend` "два") `mappend` "три"

"одиндватри"

ghci> "один" `mappend` ("два" `mappend` "три")

"одиндватри"

ghci> "один" `mappend` "два" `mappend` "три"

"одиндватри"

ghci> "бах" `mappend` mempty

"бах"

ghci> mconcat [[1,2],[3,6],[9]]

[1,2,3,6,9]

ghci> mempty :: [a]

[]

Обратите внимание, что в последней строке мы написали явную аннотацию типа. Если бы было написано просто mempty, то интерпретатор GHCi не знал бы, какой экземпляр использовать, поэтому мы должны были сказать, что нам нужен списковый экземпляр. Мы могли использовать общий тип [a] (в отличие от указания [Int] или [String]), потому что пустой список может действовать так, будто он содержит любой тип.

Поскольку функция mconcat имеет реализацию по умолчанию, мы получаем её просто так, когда определяем экземпляр класса Monoid для какого-либо типа. В случае со списком функция mconcat соответствует просто функции concat. Она принимает список списков и «разглаживает» его, потому что это равнозначно вызову оператора ++ между всеми смежными списками, содержащимися в списке.

Законы моноидов действительно выполняются для экземпляра списка. Когда у нас есть несколько списков и мы объединяем их с помощью функции mappend (или ++), не имеет значения, какие списки мы соединяем первыми, поскольку так или иначе они соединяются на концах. Кроме того, пустой список действует как единица, поэтому всё хорошо.

Обратите внимание, что моноиды не требуют, чтобы результат выражения a `mappend` b был равен результату выражения b `mappend` a. В случае со списками они очевидно не равны:

ghci> "один" `mappend` "два"

"одиндва"

ghci> "два" `mappend` "один"

"дваодин"

И это нормально. Тот факт, что при умножении выражения 3 * 5 и 5 * 3 дают один и тот же результат, – это просто свойство умножения, но оно не выполняется для большинства моноидов.

<p>Типы Product и Sum</p>

Мы уже изучили один из способов рассматривать числа как моноиды: просто позволить бинарной функции быть оператором *, а единичному значению – быть 1. Ещё один способ для чисел быть моноидами состоит в том, чтобы в качестве бинарной функции выступал оператор +, а в качестве единичного значения – значение 0:

ghci> 0 + 4

4

ghci> 5 + 0

5

ghci> (1 + 3) + 5

9

ghci> 1 + (3 + 5)

9

Законы моноидов выполняются, потому что если вы прибавите 0 к любому числу, результатом будет то же самое число. Сложение также ассоциативно, поэтому здесь у нас нет никаких проблем.

Итак, в нашем распоряжении два одинаково правомерных способа для чисел быть моноидами. Какой же способ выбрать?.. Ладно, мы не обязаны выбирать! Вспомните, что когда имеется несколько способов определения для какого-то типа экземпляра одного и того же класса типов, мы можем обернуть этот тип в декларацию newtype, а затем сделать для нового типа экземпляр класса типов по-другому. Можно совместить несовместимое.

Модуль Data.Monoid экспортирует для этого два типа: Product и Sum.

Product определён вот так:

newtype Product a = Product { getProduct :: a }

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

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

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

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

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

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

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

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

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