Класс типов Monoid
Моноид состоит из ассоциативной бинарной функции и значения, которое действует как единица (единичное или нейтральное значение) по отношению к этой функции. Когда что-то действует как единица по отношению к функции, это означает, что при вызове с данной функцией и каким-то другим значением результат всегда равен этому другому значению. Значение 1 является единицей по отношению к оператору *, а значение [] является единицей по отношению к оператору ++. В мире языка Haskell есть множество других моноидов, поэтому существует целый класс типов Monoid. Он предназначен для типов, которые могут действовать как моноиды. Давайте посмотрим, как определён этот класс типов:
class Monoid m where
mempty :: m
mappend :: m –> m –> m mconcat :: [m] –> m
mconcat = foldr mappend mempty
Класс типов Monoid определён в модуле Data.Monoid. Давайте потратим некоторое время, чтобы как следует с ним познакомиться.
Прежде всего, нам видно, что экземпляры класса Monoid могут быть определены только для конкретных типов, потому что идентификатор m в определении класса типов не принимает никаких параметров типа. В этом состоит отличие от классов Functor и Applicative, которые требуют, чтобы их экземплярами были конструкторы типа, принимающие один параметр.
Первой функцией является mempty. На самом деле это не функция, поскольку она не принимает параметров. Это полиморфная константа вроде minBound из класса Bounded. Значение mempty представляет единицу для конкретного моноида.
Далее, у нас есть функция mappend, которая, как вы уже, наверное, догадались, является бинарной. Она принимает два значения одного типа и возвращает ещё одно значение того же самого типа. Решение назвать так функцию mappend было отчасти неудачным, поскольку это подразумевает, что мы в некотором роде присоединяем два значения. Тогда как оператор ++ действительно принимает два списка и присоединяет один в конец другого, оператор * на самом деле не делает какого-либо присоединения – два числа просто перемножаются. Когда вы встретите другие экземпляры класса Monoid, вы поймёте, что большинство из них тоже не присоединяют значения. Поэтому избегайте мыслить в терминах присоединения; просто рассматривайте mappend как бинарную функцию, которая принимает два моноидных значения и возвращает третье.
Последней функцией в определении этого класса типов является mconcat. Она принимает список моноидных значений и сокращает их до одного значения, применяя функцию mappend между элементами списка. Она имеет реализацию по умолчанию, которая просто принимает значение mempty в качестве начального и сворачивает список справа с помощью функции mappend. Поскольку реализация по умолчанию хорошо подходит для большинства экземпляров, мы не будем сильно переживать по поводу функции mconcat. Когда для какого-либо типа определяют экземпляр класса Monoid, достаточно реализовать всего лишь методы mempty и mappend. Хотя для некоторых экземпляров функцию mconcat можно реализовать более эффективно, в большинстве случаев реализация по умолчанию подходит идеально.