/
Monoid.scala
59 lines (47 loc) · 1.72 KB
/
Monoid.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package cats.kernel
import scala.{ specialized => sp }
/**
* A monoid is a semigroup with an identity. A monoid is a specialization of a
* semigroup, so its operation must be associative. Additionally,
* `combine(x, empty) == combine(empty, x) == x`. For example, if we have `Monoid[String]`,
* with `combine` as string concatenation, then `empty = ""`.
*/
trait Monoid[@sp(Int, Long, Float, Double) A] extends Any with Semigroup[A] {
/**
* Return the identity element for this monoid.
*/
def empty: A
/**
* Tests if `a` is the identity.
*/
def isEmpty(a: A)(implicit ev: Eq[A]): Boolean =
ev.eqv(a, empty)
/**
* Return `a` appended to itself `n` times.
*/
override def combineN(a: A, n: Int): A =
if (n < 0) throw new IllegalArgumentException("Repeated combining for monoids must have n >= 0")
else if (n == 0) empty
else repeatedCombineN(a, n)
/**
* Given a sequence of `as`, sum them using the monoid and return the total.
*/
def combineAll(as: TraversableOnce[A]): A =
as.foldLeft(empty)(combine)
override def combineAllOption(as: TraversableOnce[A]): Option[A] =
if (as.isEmpty) None else Some(combineAll(as))
}
abstract class MonoidFunctions[M[T] <: Monoid[T]] extends SemigroupFunctions[M] {
def empty[@sp(Int, Long, Float, Double) A](implicit ev: M[A]): A =
ev.empty
def isEmpty[@sp(Int, Long, Float, Double) A](a: A)(implicit m: M[A], ev: Eq[A]): Boolean =
m.isEmpty(a)
def combineAll[@sp(Int, Long, Float, Double) A](as: TraversableOnce[A])(implicit ev: M[A]): A =
ev.combineAll(as)
}
object Monoid extends MonoidFunctions[Monoid] {
/**
* Access an implicit `Monoid[A]`.
*/
@inline final def apply[A](implicit ev: Monoid[A]): Monoid[A] = ev
}