Semigroup и Monoid: склейка с законами
Первая ступень иерархии абстракций. Semigroup это один оператор склейки и один закон, Monoid добавляет нейтральный элемент и ещё два закона. Звучит как мелочь, но именно эта пара объясняет, почему
<>работает и на строках, и на числах, и на настройках, и почемуfoldMapсобирает агрегат из чего угодно. В этом уроке: законы на пальцах, зачем нужны newtype Sum и Product, mconcat и foldMap, моноиды в конфигурациях и агрегациях, инстансы своими руками.
Идея
В уроке про свёртки ты заметил две вещи про операторы. Первая: бывают ассоциативные операторы, у которых расстановка скобок не меняет ответ. Вторая: у многих из них есть нейтральное стартовое значение, ноль для сложения, единица для умножения, пустой список для конкатенации. Тогда я обещал, что у этой пары свойств есть имена. Имена вот они.
Ассоциативный оператор склейки это Semigroup. Один метод, один закон:
class Semigroup a where
(<>) :: a -> a -> a
-- закон ассоциативности:
-- (x <> y) <> z == x <> (y <> z)
Читается <> как mappend или просто склейка. Закон не проверяется компилятором: это контракт, который ты обязан соблюсти руками, иначе всё, что построено поверх Semigroup, начнёт врать. Ровно как законы Eq и Ord из прошлого урока.
Monoid это Semigroup, у которого есть нейтральный элемент:
class Semigroup a => Monoid a where
mempty :: a
-- законы тождества:
-- mempty <> x == x (левый)
-- x <> mempty == x (правый)
mempty это значение, которое ничего не делает при склейке. Заголовок Semigroup a => Monoid a говорит то же, что Eq a => Ord a в прошлом уроке: чтобы стать Monoid, тип сначала обязан быть Semigroup. Иерархия выстраивается снизу вверх, и это первый её этаж.
Самый честный пример это список:
instance Semigroup [a] where
(<>) = (++)
instance Monoid [a] where
mempty = []
Склейка списков ассоциативна, пустой список ничего не приклеивает. Проверь в ghci:
ghci> [1, 2] <> [3, 4]
[1,2,3,4]
ghci> "при" <> "вет"
"привет"
ghci> mempty <> [1, 2, 3]
[1,2,3]
Строка это [Char], поэтому конкатенация строк это тот же инстанс. Один интерфейс, и он уже покрыл два разных типа. Дальше начинается интересное.
премиум-урок
Продолжение в премиуме: 1 200 ₽ в месяц или 10 000 ₽ в год. Вместе с ним серверные проверки задач и школьные токены AI-коуча.
Оплата пока не подключена: премиум и курсы открываются промокодом.