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

. Аналогичным образом оператор >++ – это функция, которая принимает две сущности и возвращает третью. Но вместо того, чтобы перемножать числа, она принимает два списка и конкатенирует их. И так же, как оператор >*, она имеет определённое значение, которое не изменяет другое значение при использовании с оператором >++. Этим значением является пустой список: >[].

>ghci> 4 * 1

>4

>ghci> 1 * 9

>9

>ghci> [1,2,3] ++ []

>[1,2,3]

>ghci> [] ++ [0.5, 2.5]

>[0.5,2.5]

Похоже, что оператор >* вместе с >1 и оператор >++ наряду с >[] разделяют некоторые общие свойства:

• функция принимает два параметра;

• параметры и возвращаемое значение имеют одинаковый тип;

• существует такое значение, которое не изменяет другие значения, когда используется с бинарной функцией.

Есть и ещё нечто общее между двумя этими операциями, хотя это может быть не столь очевидно, как наши предыдущие наблюдения. Когда у нас есть три и более значения и нам необходимо использовать бинарную функцию для превращения их в один результат, то порядок, в котором мы применяем бинарную функцию к значениям, неважен. Например, независимо от того, выполним ли мы >(3 * 4) * 5 или >3 * (4 * 5), результат будет равен >60. То же справедливо и для оператора >++:

>ghci> (3 * 2) * (8 * 5)

>240

>ghci> 3 * (2 * (8 * 5))

>240

>ghci> "ой" ++ ("лю" ++ "ли")

>"ойлюли"

>ghci> ("ой" ++ "лю") ++ "ли"

>"ойлюли"

Мы называем это свойство ассоциативностью. Оператор >* ассоциативен, оператор >++ тоже. Однако оператор >–, например, не ассоциативен, поскольку выражения >(5 – 3) – 4 и >5 – (3 – 4) возвращают различные результаты.

Зная об этих свойствах, мы наконец-то наткнулись на моноиды!

Класс типов Monoid

Моноид состоит из ассоциативной бинарной функции и значения, которое действует как единица (единичное или нейтральное значение) по отношению к этой функции. Когда что-то действует как единица по отношению к функции, это означает, что при вызове с данной функцией и каким-то другим значением результат всегда равен этому другому значению. Значение >1 является единицей по отношению к оператору >*, а значение >[] является единицей по отношению к оператору >++. В мире языка Haskell есть множество других моноидов, поэтому существует целый класс типов >Monoid. Он предназначен для типов, которые могут действовать как моноиды. Давайте посмотрим, как определён этот класс типов:

>class Monoid m where

>   mempty :: m

>   mappend :: m –> m –> m mconcat :: [m] –> m

>   mconcat = foldr mappend mempty

Класс типов >Monoid определён в модуле >Data.Monoid. Давайте потратим некоторое время, чтобы как следует с ним познакомиться.