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.kernel
package, 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)
}