В общем, моноид определяется в моноидальной категории, которая является категорией, которая определяет какое-то (тензорное) произведение объектов и единичного объекта.
Самое главное, категория типов является моноидальной: произведение типов a
и b
представляет собой просто тип пар (a, b)
, а тип единицы измерения - ()
.
Моноид затем определяется как объект m
с двумя морфизмами:
eta :: () -> m
mu :: (m, m) -> m
Обратите внимание, что eta
просто выбирает элемент m
, поэтому он эквивалентен mempty
, и карриmu
становится mappend
обычного класса Haskell Monoid
.
Так что это категория типов и функций, но есть также отдельная категория эндофункторов и естественных преобразований.Это также моноидальная категория.Тензорное произведение двух функторов определяется как их состав Compose f g
, а единица - единичный функтор Id
.Моноид в этой категории - монада.Как и раньше, мы выбираем объект m
, но теперь это endofunctor;и два морфизма, которые теперь являются естественными преобразованиями:
eta :: Id ~> m
mu :: Compose m m ~> m
В компонентах эти два естественных преобразования становятся:
return :: a -> m a
join :: m (m a) -> m a
Аппликативный функтор также может быть определен как моноид в функторекатегория, но с более сложным тензорным произведением под названием День свертки.Или, что то же самое, его можно определить как функтор, который (слабо) сохраняет моноидальную структуру.
Alternative
- семейство моноидов в категории типов (не эндофункторы).Это семейство генерируется аппликативным функтором f
.Для каждого типа a
у нас есть моноид, чей mempty
является элементом f a
и чей mappend
отображает пары f a
в элементы f a
.Эти полиморфные функции называются empty
и <|>
.
В частности, empty
должно быть полиморфным значением, то есть одним значением на каждый тип a
.Это, например, возможно для функтора списка, где пустой список полиморфен в a
, или для Maybe
с полиморфным значением Nothing
.Обратите внимание, что это все полиморфные типы данных, которые имеют конструктор, который не зависит от параметра типа.Интуиция заключается в том, что, если вы думаете о функторе как о контейнере, этот конструктор создает и пустой контейнер.Пустой контейнер автоматически становится полиморфным.