### Semigroup

If you have the book Learn You a Haskell for Great Good you get to start a new chapter: “Monoids.” For the website, it’s still Functors, Applicative Functors and Monoids.

First, it seems like Cats is missing `newtype`/tagged type facility. We’ll implement our own later.

Haskell’s `Monoid` is split into `Semigroup` and `Monoid` in Cats. They are also type aliases of `algebra.Semigroup` and `algebra.Monoid`. As with `Apply` and `Applicative`, `Semigroup` is a weaker version of `Monoid`. If you can solve the same problem, weaker is cooler because you’re making fewer assumptions.

LYAHFGG:

It doesn’t matter if we do `(3 * 4) * 5` or `3 * (4 * 5)`. Either way, the result is `60`. The same goes for `++`. …

We call this property associativity. `*` is associative, and so is `++`, but `-`, for example, is not.

Let’s check this:

``````import cats._, cats.syntax.all._

assert { (3 * 2) * (8 * 5) === 3 * (2 * (8 * 5)) }

assert { List("la") ++ (List("di") ++ List("da")) === (List("la") ++ List("di")) ++ List("da") }
``````

No error means, they are equal.

#### The Semigroup typeclass

Here’s the typeclass contract for `algebra.Semigroup`.

``````/**
* A semigroup is any set `A` with an associative operation (`combine`).
*/
trait Semigroup[@sp(Int, Long, Float, Double) A] extends Any with Serializable {

/**
* Associative operation taking which combines two values.
*/
def combine(x: A, y: A): A

....
}
``````

This enables `combine` operator and its symbolic alias `|+|`. Let’s try using this.

``````List(1, 2, 3) |+| List(4, 5, 6)
// res2: List[Int] = List(1, 2, 3, 4, 5, 6)

"one" |+| "two"
// res3: String = "onetwo"
``````

#### The Semigroup Laws

Associativity is the only law for `Semigroup`.

• associativity `(x |+| y) |+| z = x |+| (y |+| z)`

Here’s how we can check the Semigroup laws from the REPL. Review Checking laws with discipline for the details:

``````scala> import cats._, cats.data._, cats.implicits._
import cats._
import cats.data._
import cats.implicits._

scala> import cats.kernel.laws.GroupLaws
import cats.kernel.laws.GroupLaws

scala> val rs1 = GroupLaws[Int].semigroup(Semigroup[Int])
rs1: cats.kernel.laws.GroupLaws[Int]#GroupProperties = cats.kernel.laws.GroupLaws\$GroupProperties@5a077d1d

scala> rs1.all.check
+ semigroup.associativity: OK, passed 100 tests.
+ semigroup.combineN(a, 1) == a: OK, passed 100 tests.
+ semigroup.combineN(a, 2) == a |+| a: OK, passed 100 tests.
+ semigroup.serializable: OK, proved property.
``````

#### Lists are Semigroups

``````List(1, 2, 3) |+| List(4, 5, 6)
// res4: List[Int] = List(1, 2, 3, 4, 5, 6)
``````

#### Product and Sum

For `Int` a semigroup can be formed under both `+` and `*`. Instead of tagged types, cats provides only the instance additive.

Trying to use operator syntax here is tricky.

``````def doSomething[A: Semigroup](a1: A, a2: A): A =
a1 |+| a2

doSomething(3, 5)(Semigroup[Int])
// res5: Int = 8
``````

I might as well stick to function syntax:

``````Semigroup[Int].combine(3, 5)
// res6: Int = 8
``````