How to write length function for all Monoids

A monoid, in the general case, as no notion of length. Take for instance Sum Int, which is Int equipped with addition for its monoidal operation. We have

Sum 3 <> Sum 4 = Sum 7 = Sum (-100) <> Sum 7 <> Sum (100)

What should be its "length"? There is no real notion of length here, since the underlying type is Int, which is not a list-like type.

Another example: Endo Int which is Int -> Int equipped with composition. E.g.

Endo (\x -> x+1) <> Endo (\x -> x*2) = Endo (\x -> 2*x+1)

Again, no meaningful "length" can be defined here.

You can browse Data.Monoid and see other examples where there is no notion of "length".

Const a is also a (boring) monoid with no length.

Now, it is true that lists [a] form a monoid (the free monoid over a), and length can indeed be defined there. Still, this is only a particular case, which does not generalize.


The Semigroup and Monoid interfaces provide a means to build up values, (<>). They don't, however, give us a way to break down or otherwise extract information from values. That being so, a length generalised beyond some specific type requires a different abstraction.

As discussed in the comments to chi's answer, while Data.Foldable offers a generalised length :: Foldable t => t a -> Int, it isn't quite what you were aiming at -- in particular, the connection between Foldable and Monoid is that foldable structures can be converted to lists/the free monoid, and not that foldables themselves are necessarily monoids.

One other possibility, which is somewhat obscure but closer to the spirit of your question, is the Factorial class from the monoid-subclasses package, a subclass of Semigroup. It is built around factors :: Factorial m => m -> [m], which splits a value into irreducible factors, undoing what sconcat or mconcat do. A generalised length :: Factorial m => m -> Int can then be defined as the length of the list of factors. In any case, note that we still end up needing a further abstraction on the top of Semigroup/Monoid.

Tags:

Haskell