Тип данных не может быть моноидом сам по себе. Для моноида вам нужен тип данных T
и еще две вещи:
- ассоциативная двоичная операция , назовем ее
|+|
, которая принимает два элемента типа T
и создает элемент типа T
- элемент идентификации типа
T
, назовем его i
, так что для каждого элемента t
типа T
выполняется следующее: t |+| i = i |+| t = t
Вот несколько примеров моноида:
- набор целых чисел с операцией = сложение и тождество = ноль
- набор целых чисел с операцией = умножение и тождество = один
- набор списков с операцией = добавление и тождество = пустой список
- набор строк с операцией = объединение и тождество = пустая строка
моноидный гомоморфизм
Моноид конкатенации строк можно преобразовать в моноид сложения целых чисел, применив .length
ко всем его элементам. Оба этих набора образуют моноид. Кстати, помните, что мы не можем просто сказать «множество целых чисел образует моноид»; мы должны выбрать ассоциативную операцию и соответствующий элемент идентичности. Если мы возьмем, например, деление как операция, мы нарушаем первое правило (вместо создания элемента типа integer мы можем создать элемент типа float / double).
Метод length
позволяет нам перейти от моноида (конкатенация строк) к другому моноиду (сложение целых чисел). Если такая операция также сохраняет моноидную структуру, она считается моноидным гомоморфизмом .
Сохранение структуры означает:
length(t1 |+| t2) = length(t1) |+| length(t2)
and
length(i) = i'
, где t1
и t2
представляют элементы моноида "источник", i
- идентификатор моноида "источник", а i'
- идентификатор моноида "назначения". Вы можете попробовать это сами и увидеть, что length
действительно является структурно-сохраняющей операцией на моноиде конкатенации строк, в то время как, например, indexOf("a")
нет.
Моноидный изоморфизм
Как показано, length
отображает все строки в соответствующие им целые числа и образует моноид с добавлением в качестве операции и нулем в качестве тождества. Но мы не можем вернуться назад - для каждой строки мы можем выяснить ее длину, но, учитывая длину, мы не можем восстановить «исходную» строку. Если бы мы могли, тогда операция «идти вперед» в сочетании с операцией «идти назад» сформировала бы моноидный изоморфизм .
Изоморфизм означает способность идти туда и обратно без потери информации. Например, как указывалось ранее, список образует моноид при добавлении в качестве операции и пустой список в качестве элемента идентичности. Мы можем перейти от «список при добавлении» к моноиду «вектор при добавлении» и обратно без потери информации, что означает, что операции .toVector
и .toList
вместе образуют изоморфизм. Другой пример изоморфизма, о котором Рунар упоминал в своем тексте, это String
⟷ List[Char]
.