Моноид (M,•,1)
- это математическая структура, такая что:
M
это набор
1
является членом M
• : M * M -> M
a•1 = a = 1•a
- Учитывая элементы
a
, b
и c
в M
, мы имеем a•(b•c) = (a•b)•c
.
Свободный моноид на множестве M
- это моноид (M',•,0)
и функция e : M -> M'
, такая, что для любого моноида (N,*,1)
при заданной (установленной) карте f : M -> N
мы можем расширить это до морфизма моноидов. f' : (M',•,0) -> (N,*,1)
, т.е.
f a = f' (e a)
f' 0 = 1
f' (a•b) = (f' a) • (f' b)
Другими словами, это моноид, который не делает ничего особенного.
Примером моноида являются целые числа с добавляемой операцией и тождеством, равным 0. Другой моноид - это последовательности целых чисел с объединенной операцией, а тождество - пустая последовательность. Теперь добавляемые целые числа не являются свободным моноидом на целых числах. Рассмотрим карту на последовательности целых чисел, принимающих от n
до (n)
. Тогда для того, чтобы это было бесплатным, нам нужно было бы распространить это на карту, взяв n + m
до (n,m)
, т.е. это должно занять 0
до (0)
и до (0,0)
и до (0,0,0)
и так далее.
С другой стороны, если мы попытаемся рассматривать последовательности целых чисел как свободный моноид на целых числах, мы увидим, что в этом случае это работает. Расширение карты на целые числа с добавлением - это то, которое принимает сумму последовательности (с суммой (), равной 0).
Так что же такое свободный моноид на множестве S
? Ну, одну вещь, которую мы могли бы попробовать, это просто произвольные двоичные деревья S
. В типе Haskell это будет выглядеть так:
data T a = Unit | Single a | Conc (T a) (T a)
И он будет иметь идентичность Unit
, e = Single
и (•) = Conc
.
И мы можем написать функцию, чтобы показать, как она бесплатна:
-- here the second argument represents a monoid structure on b
free :: (a -> b) -> (b -> b -> b, b) -> T a -> b
free f ((*),zero) = f' where
f' (Single a) = f a
f' Unit = zero
f' (Conc a b) = f' a * f' b
Должно быть совершенно очевидно, что это удовлетворяет требуемым законам для свободного моноида на a
. За исключением одного: T a
не является моноидом, потому что оно не совсем соответствует законам 4 или 5.
Так что теперь мы должны спросить, можем ли мы превратить это в более простой свободный моноид, то есть тот, который является настоящим моноидом. Ответ - да. Одним из способов является наблюдение, что Conc Unit a
и Conc a Unit
и Single a
должны быть одинаковыми. Итак, давайте сделаем первые два типа непредставимыми:
data TInner a = Single a | Conc (TInner a) (TInner a)
data T a = Unit | Inner (TInner a)
Второе наблюдение, которое мы можем сделать, заключается в том, что не должно быть никакой разницы между Conc (Conc a b) c
и Conc a (Conc b c)
. Это связано с законом 5 выше. Затем мы можем сгладить наше дерево:
data TInner a = Single a | Conc (a,b,[a])
data T a = Unit | Inner (TInner a)
Странная конструкция с Conc
силами состоит в том, чтобы иметь только один способ представлять Single a
и Unit
. Но мы видим, что мы можем объединить их все вместе: измените определение Conc
на Conc [a]
, а затем мы можем изменить Single x
на Conc [x]
и Unit
на Conc []
, чтобы мы получили:
data T a = Conc [a]
Или мы можем просто написать:
type T a = [a]
И операции:
unit = []
e a = [a]
(•) = append
free f ((*),zero) = f' where
f' [] = zero
f' (x:xs) = f x * f' xs
Так что в Хаскеле тип списка называется свободным моноидом.