Изучай Haskell во имя добра! (Липовача) - страница 206



Прежде всего, нам видно, что экземпляры класса >Monoid могут быть определены только для конкретных типов, потому что идентификатор >m в определении класса типов не принимает никаких параметров типа. В этом состоит отличие от классов >Functor и >Applicative, которые требуют, чтобы их экземплярами были конструкторы типа, принимающие один параметр.

Первой функцией является >mempty. На самом деле это не функция, поскольку она не принимает параметров. Это полиморфная константа вроде >minBound из класса >Bounded. Значение >mempty представляет единицу для конкретного моноида.

Далее, у нас есть функция >mappend, которая, как вы уже, наверное, догадались, является бинарной. Она принимает два значения одного типа и возвращает ещё одно значение того же самого типа. Решение назвать так функцию >mappend было отчасти неудачным, поскольку это подразумевает, что мы в некотором роде присоединяем два значения. Тогда как оператор >++ действительно принимает два списка и присоединяет один в конец другого, оператор >* на самом деле не делает какого-либо присоединения – два числа просто перемножаются. Когда вы встретите другие экземпляры класса >Monoid, вы поймёте, что большинство из них тоже не присоединяют значения. Поэтому избегайте мыслить в терминах присоединения; просто рассматривайте >mappend как бинарную функцию, которая принимает два моноидных значения и возвращает третье.

Последней функцией в определении этого класса типов является >mconcat. Она принимает список моноидных значений и сокращает их до одного значения, применяя функцию >mappend между элементами списка. Она имеет реализацию по умолчанию, которая просто принимает значение >mempty в качестве начального и сворачивает список справа с помощью функции >mappend. Поскольку реализация по умолчанию хорошо подходит для большинства экземпляров, мы не будем сильно переживать по поводу функции >mconcat. Когда для какого-либо типа определяют экземпляр класса >Monoid, достаточно реализовать всего лишь методы >mempty и >mappend. Хотя для некоторых экземпляров функцию >mconcat можно реализовать более эффективно, в большинстве случаев реализация по умолчанию подходит идеально.

Законы моноидов

Прежде чем перейти к более конкретным экземплярам класса >Monoid, давайте кратко рассмотрим законы моноидов.

Вы узнали, что должно иметься значение, которое действует как тождество по отношению к бинарной функции, и что бинарная функция должна быть ассоциативна. Можно создать экземпляры класса >Monoid, которые не следуют этим правилам, но такие экземпляры никому не нужны, поскольку, когда мы используем класс типов