# Monoid & MonoidK

In continuation to previous post.

There is no documentation for MonoidK (Monoid for higher Kinds) on the cats site, hence let me try explaining it. Though Monoid first.

### Monoid

`Monoid[T]` technically is a Semigroup with an `empty`/`Identity` function. i.e. There are two main properties:

• Associativity (From Semigroup)
• Identity

Roughly:

```trait Monoid[T]{
/**
combine is defined as:
`(a combine b) combine c =
a combine (b combine c)`
*/
def combine(x:T, y:T): T

/**
empty is defined as: `A o empty = empty o A = A`
*/
def empty : T
}
```

An example:

```    implicit def intMonoid = new Monoid[Int]{
override def empty: Int = 0
override def combine(x: Int, y: Int): Int = x + y
}
Semigroup[Int].combine(1,2) // returns 3

implicit def listMonoid[T](implicit ev: Monoid[T]): Monoid[List[T]] = new Monoid[List[T]]{
override def empty: List[T] = List()
override def combine(x: List[T], y: List[T]): List[T] = x ::: y
}
Semigroup[List[Int]].combine(List(1,2), List(3,4)) //gives List(1,2,3,4)

implicit def optionMonoid[T](implicit ev: Monoid[T]) : Monoid[Option[T]] = new Monoid[Option[T]]{
override def empty: Option[T] = None

override def combine(x: Option[T], y: Option[T]): Option[T] = x match {
case Some(a) => y match {
case Some(b) => Some(ev.combine(a, b))
case None => None
}
case None => y
}
}

Semigroup[Option[Int]].combine(Option(1), Some(2)) //gives Option(3)

//This is quite awesome in the sense, that it even works for its inner type automatically. It is same as:

Semigroup.apply[Option[Int]](optionMonoid[Int](intMonoid)).combine(Option[Int](1), Some[Int](2));

//Many standard Monoids are available under below imports
import cats._
import cats.std.all._

Monoid[String].combineAll(List())
Monoid[Map[String,Int]].combineAll(List(Map("a" -> 1, "b" -> 2), Map("a" -> 3)))
//Returns Map(b -> 2, a -> 4)
```

## MonoidK

MonoidK is a Monoid for a kind (K stands for Kind). This is how it is roughly defined:

```trait MonoidK[F[_]]{

def combine[A](x:F[A], y:F[A]): F[A]
def empty[A] : F[A]
}
```

We basically define the typeconstructor while declaring the `MonoidK` object and later define the type argument while calling `combine`. Its like you are working on the container and work based on its proper type provided later. One important thing to notice is that, you dont really stand a chance to work in nested. Example:

```implicit def Ksemi[T]: SemigroupK[Option] = new SemigroupK[Option]{
override def combine[A](x: Option[A], y: Option[A]): Option[A] = x orElse y
}

SemigroupK[Option].combine(Option(1), Option(2)) // returns Option(1)

implicit def listK : MonoidK[List] = new MonoidK[List] {
override def empty[A]: List[A] = List()
override def combine[A](x: List[A], y: List[A]): List[A] = x ::: y
}

MonoidK[List].combine(List(1,2,3),List(4))
```

When we define `SemigroupK[Option]`, we actually provide the type constructor. Doing so, leaves us no chance to provide implicit Monoid for its type parameter. So the behavior of `combine` is purely based on the container rather than the type argument.