Когда мы объединяем значения типа >All
с помощью функции >mappend
, результатом будет >True
только в случае, если все значения, использованные в функции >mappend
, равны >True
:
>ghci> getAll $ mempty `mappend` All True
>True
>ghci> getAll $ mempty `mappend` All False
>False
>ghci> getAll . mconcat . map All $ [True, True, True]
>True
>ghci> getAll . mconcat . map All $ [True, True, False]
>False
Так же, как при использовании умножения и сложения, мы обычно явно указываем бинарные функции вместо оборачивания их в значения >newtype
и последующего использования функций >mappend
и >mempty
. Функция >mconcat
кажется полезной для типов >Any
и >All
, но обычно проще использовать функции >or
и >and
. Функция >or
принимает списки значений типа >Bool
и возвращает >True
, если какое-либо из них равно >True
. Функция >and
принимает те же значения и возвращает значение >True
, если все из них равны >True
.
Помните тип >Ordering
? Он используется в качестве результата при сравнении сущностей и может иметь три значения: >LT
, >EQ
и >GT
, которые соответственно означают «меньше, чем», «равно» и «больше, чем».
>ghci> 1 `compare` 2
>LT
>ghci> 2 `compare` 2
>EQ
>ghci> 3 `compare` 2
>GT
При использовании чисел и значений типа >Bool
поиск моноидов сводился к просмотру уже существующих широко применяемых функций и их проверке на предмет того, проявляют ли они какое-либо поведение, присущее моноидам. При использовании типа >Ordering
нам придётся приложить больше старания, чтобы распознать моноид. Оказывается, его экземпляр класса >Monoid
настолько же интуитивен, насколько и предыдущие, которые мы уже встречали, и кроме того, весьма полезен:
>instance Monoid Ordering where
> mempty = EQ
> LT `mappend` _ = LT
> EQ `mappend` y = y
> GT `mappend` _ = GT
Экземпляр определяется следующим образом: когда мы объединяем два значения типа >Ordering
с помощью функции >mappend
, сохраняется значение слева, если значение слева не равно >EQ
. Если значение слева равно >EQ
, результатом будет значение справа. Единичным значением является >EQ
. На первый взгляд, такой выбор может показаться несколько случайным, но на самом деле он имеет сходство с тем, как мы сравниваем слова в алфавитном порядке. Мы смотрим на первые две буквы, и, если они отличаются, уже можем решить, какое слово шло бы первым в словаре. Если же первые буквы равны, то мы переходим к сравнению следующей пары букв, повторяя процесс[13].
Например, сравнивая слова «ox» и «on», мы видим, что первые две буквы каждого слова равны, а затем продолжаем сравнивать вторые буквы. Поскольку «x» в алфавите идёт после «