Monoids

Contents
mempty and mappend
The common instances
Sum, Product, Any, All
Combining records

mempty and mappend

A monoid is a type with an associative binary operation and an identity element. Those two facts are enough to fold a whole list without knowing anything about the values:

class Semigroup a => Monoid a where mempty :: a mappend :: a -> a -> a mempty :: [Int] -- [] [1,2] <> [3] -- [1,2,3]

<> is the modern name for mappend, and it belongs to Semigroup. The monoid adds the empty value that the semigroup lacks.

The common instances

Four instances appear in everyday code. Each one answers the same question: what is the empty value, and how do two values combine?

-- lists concatenate, empty is [] [1] <> [2] -- [1,2] -- strings are lists of characters "ab" <> "cd" -- "abcd" -- Maybe keeps the first Just Just 1 <> Just 2 -- Just 1 Nothing <> Just 2 -- Just 2

The Maybe instance is the one that surprises people: it is not addition, it is the first available value. Use it to pick the first successful result from a list.

Sum, Product, Any, All

Numbers have two reasonable monoids, so the library wraps them in newtypes instead of picking one. This is the payoff of lesson 27:

getSum (Sum 2 <> Sum 3) -- 5 getProduct (Product 2 <> Product 3) -- 6 getAny (Any False <> Any True) -- True getAll (All True <> All False) -- False

Any is logical or with False as the identity, and All is logical and with True. Both give a fold over a list of booleans for free.

Combining records

The most useful application is merging partial results. Write the instance once and a fold over a list of records does the rest:

data Stats = Stats { count :: Sum Int , total :: Sum Int } deriving (Show) instance Semigroup Stats where a <> b = Stats (count a <> count b) (total a <> total b) instance Monoid Stats where mempty = Stats mempty mempty

Now foldMap over a list of records sums every field at once, and a new field only means one more line in the instance.

Next: Traversable

Article author: Arthur Isaev

Related articles
Haskell
Haskell course: zero to hero in 50 lessons
What is Haskell and why it matters
Install the toolchain with GHCup
GHCi: the interactive shell
Your first program
Values with let and where
Types and type signatures
Functions and application
Currying and partial application
Operators, sections, and fixity
if, guards, and pattern guards
case expressions
Pattern matching
Tuples
Lists
Ranges and enumeration
List comprehensions
Recursion replaces loops
map, filter, and foldr
Lambdas and composition
Type classes
Parametric polymorphism
Maybe and null safety
Either and recoverable errors
data: product types
data: sum types
Records
newtype and type synonyms
Recursive data: binary trees
Functor
Applicative
Monad
do notation
IO and purity
Files and IO
Modules and imports
Cabal projects
Dependencies
Testing with HUnit
Property testing with QuickCheck
Laziness and infinite lists
Strictness and space leaks
Folds
Monoids
Traversable
Monad transformers
Errors and exceptions
Concurrency
Parsing with Megaparsec
Capstone: a todo CLI
Hero roadmap: the whole course on one page
Banner image

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: