Skip to content

Commit

Permalink
Merge pull request #517 from philwills/monoid-doc-foldmap
Browse files Browse the repository at this point in the history
Add an example using foldMap on to a tuple
  • Loading branch information
adelbertc committed Sep 3, 2015
2 parents 05deff3 + cd5471d commit 672e010
Showing 1 changed file with 45 additions and 10 deletions.
55 changes: 45 additions & 10 deletions docs/src/main/tut/monoid.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ source: "https://github.com/non/algebra/blob/master/core/src/main/scala/algebra/
---
# Monoid

`Monoid` extends the [`Semigroup`](semigroup.html) typeclass, adding an `empty` method to semigroup's
`combine`. The `empty` method must return a value that when combined with any other instance of that type
returns the other instance, i.e.
`Monoid` extends the [`Semigroup`](semigroup.html) type class, adding an
`empty` method to semigroup's `combine`. The `empty` method must return a
value that when combined with any other instance of that type returns the
other instance, i.e.

(combine(x, empty) == combine(empty, x) == x)

For example, if we have a `Monoid[String]` with `combine` defined as string concatenation, then `empty = ""`.
For example, if we have a `Monoid[String]` with `combine` defined as string
concatenation, then `empty = ""`.

Having an `empty` defined allows us to combine all the elements of some potentially empty collection
of `T` for which a `Monoid[T]` is defined and return a `T`, rather than an `Option[T]` as we have a
sensible default to fall back to.
Having an `empty` defined allows us to combine all the elements of some
potentially empty collection of `T` for which a `Monoid[T]` is defined and
return a `T`, rather than an `Option[T]` as we have a sensible default to
fall back to.

```tut
import cats._
Expand All @@ -28,8 +31,9 @@ Monoid[String].combineAll(List("a", "b", "c"))
Monoid[String].combineAll(List())
```

The advantage of using these typeclass provided methods, rather than the specific ones for each
type, is that we can compose monoids to allow us to operate on more complex types, e.g.
The advantage of using these type class provided methods, rather than the
specific ones for each type, is that we can compose monoids to allow us to
operate on more complex types, e.g.

```tut
import cats._
Expand All @@ -38,9 +42,40 @@ import cats.std.all._
Monoid[Map[String,Int]].combineAll(List(Map("a" -> 1, "b" -> 2), Map("a" -> 3)))
Monoid[Map[String,Int]].combineAll(List())
```

This is also true if we define our own instances. As an example, let's use
[`Foldable`](foldable.html)'s `foldMap`, which maps over values accumulating
the results, using the available `Monoid` for the type mapped onto. To use this
with a function that produces a tuple, we can define a `Monoid` for a tuple
that will be valid for any tuple where the types it contains also have a
`Monoid` available:

```tut
import cats._
import cats.implicits._
val l = List(1, 2, 3, 4, 5)
l.foldMap(identity)
l.foldMap(i => i.toString)
implicit def tupleMonoid[A : Monoid, B : Monoid]: Monoid[(A, B)] =
new Monoid[(A, B)] {
def combine(x: (A, B), y: (A, B)): (A, B) = {
val (xa, xb) = x
val (ya, yb) = y
(Monoid[A].combine(xa, ya), Monoid[B].combine(xb, yb))
}
def empty: (A, B) = (Monoid[A].empty, Monoid[B].empty)
}
l.foldMap(i => (i, i.toString)) // do both of the above in one pass, hurrah!
```

-------------------------------------------------------------------------------

N.B.
Cats does not define a `Monoid` typeclass itself, it uses the [`Monoid`
Cats does not define a `Monoid` type class itself, it uses the [`Monoid`
trait](https://github.com/non/algebra/blob/master/core/src/main/scala/algebra/Monoid.scala)
which is defined in the [algebra project](https://github.com/non/algebra) on
which it depends. The [`cats` package object](https://github.com/non/cats/blob/master/core/src/main/scala/cats/package.scala)
Expand Down

0 comments on commit 672e010

Please sign in to comment.