# 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`

.