Search code examples
haskellfunctional-programmingcategory-theory

Why prefer monoids over semigroups in Haskell? Why do we need mempty?


I can understand the reason for mappend and associativity requirement for it. But why do we need the identity element what is the pragmatic usefulness in it? Or maybe I've missed something important and without definition of it in instances the whole logic won't work. Thank you!


Solution

  • The mempty certainly is needed for some applications. For instance, what should be the result of foldMapping over an empty list? There's no a value you could feed the mapped function to obtain an m. So, there needs to be a “default”. It's nice if this is an identity element of an associative operation – for example it allows arbitrary reordering/chunking the fold without changing the result. When folding over a tree, actually a lot of memptys may show up in the middle but you always know they will get “squeezed out” in the end result, so you don't depend on the exact tree layout for reproducable results.

    That said, you're right with your concern: Semigroup would quite often be sufficient, and it would probably be better if this class were used wherever mempty isn't needed (since there are actually a few quite nifty types that are Semigroup but not Monoid). However, the early design of the standard library apparently did not consider this important enough to warrant the extra class, so lots of code came to rely on Monoid without really needing a monoid.

    So – much the same issue as we used to have with Monad: lots of code really only needed Applicative or even just Functor, but for historical reasons was stuck with Monad anyway until the AMP. Ultimately the problem is that Haskell class hierarchies can't really be refined after the fact, only extended downwards, not upwards.