In category theory, a monad is the composition of two adjoint functors. For example, the Maybe monad is the free pointed-set functor composed with the forgetful functor. Likewise, the List monad is the free monoid functor composed with the forgetful functor.
Monoid is one of the simplest algebraic structures, so I wonder if programming can benefit from more complex ones. I didn't find the free group monad in standard Haskell packages, so I'll define it here
data FreeGroup a = Nil | PosCons a (FreeGroup a) | NegCons a (FreeGroup a)
The ==
operator is defined such that NegCons x (PosCons x y) == y
. Accordingly, in length :: FreeGroup a -> Int
, each PosCons
is counted +1 and each NegCons
-1 (it is the only group morphism to Int that values +1 on each PosCons).
As in lists (free monoids), concat
is just multiplication and map
is the functorial lift of functions. So the monad instance of FreeGroup
is exactly the same as that of List
.
Does the free group monad have any programming uses ? Also, there is often an interpretation of a monad as a value in a context : for List
the context would be choice or uncertainty. Is there such an interpretation for the free group monad ?
How about free rings and vector spaces (which are always free) ?
For any algebraic structure S
, the existence of a categorical free functor FS :: Set -> S
means the existence of a function Haskell calls fold :
foldS :: S s => (a -> s) -> FS a -> s
It lifts a function on the basis a
to an S
-morphism on the free object FS a
. The usual foldr
function is a specialization of foldMonoid
(called foldMap
in Haskell, for some reason I don't quite get), the monoid being the set of functions b -> b
with composition as multiplication.
For the sake of completeness, here is the monad instance of FreeGroup
:
mult :: FreeGroup a -> FreeGroup a -> FreeGroup a
mult Nil x = x
mult x Nil = x
mult (PosCons x y) z = PosCons x (mult y z)
mult (NegCons x y) z = NegCons x (mult y z)
inverse :: FreeGroup a -> FreeGroup a
inverse Nil = Nil
inverse (PosCons x y) = mult (inverse y) (NegCons x Nil)
inverse (NegCons x y) = mult (inverse y) (PosCons x Nil)
groupConcat :: FreeGroup (FreeGroup a) -> FreeGroup a
groupConcat Nil = Nil
groupConcat (PosCons x l) = mult x (groupConcat l)
groupConcat (NegCons x l) = mult (inverse x) (groupConcat l)
instance Functor FreeGroup where
fmap f Nil = Nil
fmap f (PosCons x y) = PosCons (f x) (fmap f y)
fmap f (NegCons x y) = NegCons (f x) (fmap f y)
instance Applicative FreeGroup where
pure x = PosCons x Nil
fs <*> xs = do { f <- fs; x <- xs; return $ f x; }
instance Monad FreeGroup where
l >>= f = groupConcat $ fmap f l
NegCons x (PosCons x y) == y
, you need anEq
instance for thea
inFreeGroup a
. You cannot force that. I doubtFreeGroup
is a monad in haskell. – Frankyinstance Eq a => Eq [a]
. The monad definition doesn't need the==
operator, I just spoke of it the explain the link betweenPosCons
andNegCons
. – V. SemeriaEq
constraint here like in the example you gave in the comment because forMonad
you don't have "access" to the type argument. You cannot put anEq
constraint oninstance Monad FreeGroup where ...
. I guess this could work if you avoid equality by not having the Monad instance put it in any sort of normal form. – David Youngtype instance Element (FreeGroup a) = a
and theninstance Eq a => MonoFoldable (FreeGroup a) where ...
. TheofoldMap
implementation will have to collapse positive and negative elements appropriately. You'll probably also wantnormalize :: Eq a => FreeGroup a -> FreeGroup a
. The need to normalize manually, and track normalization without help from the type checker, is probably the biggest barrier to making this useful. – dfeuer