является экземпляром
>Monoid
для всех значений типа
>a
, для которых уже имеется экземпляр класса
>Num
. Для того чтобы использовать тип
>Product a
в качестве моноида, мы должны произвести некоторое оборачивание и разворачивание
>newtype
:
>ghci> getProduct $ Product 3 `mappend` Product 9
>27
>ghci> getProduct $ Product 3 `mappend` mempty
>3
>ghci> getProduct $ Product 3 `mappend` Product 4 `mappend` Product 2
>24
>ghci> getProduct . mconcat . map Product $ [3,4,2]
>24
Тип >Sum
определён в том же духе, что и тип >Product
, и экземпляр тоже похож. Мы используем его точно так же:
>ghci> getSum $ Sum 2 `mappend` Sum 9
>11
>ghci> getSum $ mempty `mappend` Sum 3
>3
>ghci> getSum . mconcat . map Sum $ [1,2,3]
>6
Ещё одним типом, который может действовать как моноид двумя разными, но одинаково допустимыми способами, является >Bool
. Первый способ состоит в том, чтобы заставить функцию >||
, которая представляет собой логическое ИЛИ, действовать как бинарная функция, используя >False
в качестве единичного значения. Если при использовании логического ИЛИ какой-либо из параметров равен >True
, функция возвращает >True
; в противном случае она возвращает >False
. Поэтому если мы используем >False
в качестве единичного значения, операция ИЛИ вернёт >False
при использовании с >False
– и >True
при использовании с >True
. Конструктор >newtype Any
аналогичным образом имеет экземпляр класса >Monoid
. Он определён вот так:
>newtype Any = Any { getAny :: Bool }
> deriving (Eq, Ord, Read, Show, Bounded)
А его экземпляр выглядит так:
>instance Monoid Any where
> mempty = Any False
> Any x `mappend` Any y = Any (x || y)
Он называется >Any
, потому что >x `mappend` y
будет равно >True
, если любое из этих двух значений равно >True
. Даже когда три или более значений >Bool
, обёрнутых в >Any
, объединяются с помощью функции >mappend
, результат будет содержать >True
, если любое из них равно >True
.
>ghci> getAny $ Any True `mappend` Any False
>True
>ghci> getAny $ mempty `mappend` Any True
>True
>ghci> getAny . mconcat . map Any $ [False, False, False, True]
>True
>ghci> getAny $ mempty `mappend` mempty
>False
Другой возможный вариант экземпляра класса >Monoid
для типа >Bool
– всё как бы наоборот: заставить оператор >&&
быть бинарной функцией, а затем сделать значение >True
единичным значением. Логическое И вернёт >True
, только если оба его параметра равны >True
.
Это объявление >newtype
:
>newtype All = All { getAll :: Bool }
> deriving (Eq, Ord, Read, Show, Bounded)
А это экземпляр:
>instance Monoid All where
> mempty = All True
> All x `mappend` All y = All (x && y)
Когда мы объединяем значения типа