Monoids Cats
Monoid Type Class
cats.kernel.Monoid (aliased cats.Monoid) extends cats.external.Semigroup (alias cats.Semigroup).
Cats Kernel
A subproject of Cats to provide a small set of type classes for libraries that don't need the full Cats toolbox. They are in the
cats.kernelpackage, but they are aliased ascats.
Monoid Instances
Monoid has the same Cats pattern for the user interface, a companion object has an apply method.
import cats.Monoid
import cats.instances.string._ // for Monoid
Monoid[String].combine("Hi ", "there")
// res0: String = Hi there
Monoid[String].empty
// res1: String = ""
is the same thing as:
Monoid.apply[String].combine("Hi ", "there")
// res2: String = Hi there
Monoid.apply[String].empty
// res3: String = ""
and if we don't need empty, then we can do this instead:
import cats.Semigroup
Semigroup[String].combine("Hi ", "there")
// res4: String = Hi there
Monoid Syntax
Cats provides syntax for combine with |+|. It technically comes from Semigroup, so we need cats.syntax.semigroup:
import cats.instances.string._ // for Monoid
import cats.syntax.semigroup._ // for |+|
val stringResult = "Hi " |+| "there" |+| Monoid[String].empty
// stringResult: String = Hi there
import cats.instances.int._ // for Monoid
val intResult = 1 |+| 2 |+| Monoid[Int].empty
// intResult: Int = 3
Example
A function that adds: def add(items: List[Int]): Int
def add(items: List[Int]): Int = items.foldLeft(0)(_ + _)
//or
import cats.Monoid
import cats.instances.int._
import cats.syntax.semigroup._
def add(items: List[Int]): Int =
items.foldLeft(Monoid[Int].empty)(_ |+| _)
A function that now adds List[Option[Int]]:
//Make it generic!!
import cats.Monoid
import cats.syntax.semigroup._ // for |+|
def add[A](items: List[A])(implicit monoid: Monoid[A]): A =
items.foldLeft(monoid.empty)(_ |+| _)
Equivalently with context bounds syntax:
def add[A: Monoid](items: List[A]): A =
items.foldLeft(Monoid[A].empty)(_ |+| _)
import cats.instances.int._ // for Monoid
add(List(1, 2, 3))
// res9: Int = 6
import cats.instances.option._ // for Monoid
add(List(Some(1), None, Some(2), None, Some(3)))
// res10: Option[Int] = Some(6)
Now we want to sum of Order's
case class Order(totalCost: Double, quantity: Double)
implicit val monoid: Monoid[Order] = new Monoid[Order] {
def combine(o1: Order, o2: Order) =
Order(
o1.totalCost + o2.totalCost,
o1.quantity + o2.quantity
)
def empty = Order(0, 0)
}