/core/src/main/scala/scalaz/Monoid.scala

http://github.com/scalaz/scalaz · Scala · 150 lines · 74 code · 24 blank · 52 comment · 4 complexity · 2bd2ac38bb80e2d44f0698dcef7a0939 MD5 · raw file

  1. package scalaz
  2. ////
  3. /**
  4. * Provides an identity element (`zero`) to the binary `append`
  5. * operation in [[scalaz.Semigroup]], subject to the monoid laws.
  6. *
  7. * Example instances:
  8. * - `Monoid[Int]`: `zero` and `append` are `0` and `Int#+` respectively
  9. * - `Monoid[List[A]]`: `zero` and `append` are `Nil` and `List#++` respectively
  10. *
  11. * References:
  12. * - [[http://mathworld.wolfram.com/Monoid.html]]
  13. *
  14. * @see [[scalaz.syntax.MonoidOps]]
  15. * @see [[scalaz.Monoid.MonoidLaw]]
  16. *
  17. */
  18. ////
  19. trait Monoid[F] extends Semigroup[F] { self =>
  20. ////
  21. /** The identity element for `append`. */
  22. def zero: F
  23. // derived functions
  24. /**
  25. * For `n = 0`, `zero`
  26. * For `n = 1`, `append(zero, value)`
  27. * For `n = 2`, `append(append(zero, value), value)`
  28. */
  29. def multiply(value: F, n: Int): F =
  30. if (n <= 0) zero else multiply1(value, n - 1)
  31. /** Whether `a` == `zero`. */
  32. def isMZero(a: F)(implicit eq: Equal[F]): Boolean =
  33. eq.equal(a, zero)
  34. final def ifEmpty[B](a: F)(t: => B)(f: => B)(implicit eq: Equal[F]): B =
  35. if (isMZero(a)) { t } else { f }
  36. final def onNotEmpty[B](a: F)(v: => B)(implicit eq: Equal[F], mb: Monoid[B]): B =
  37. ifEmpty(a)(mb.zero)(v)
  38. final def onEmpty[A,B](a: F)(v: => B)(implicit eq: Equal[F], mb: Monoid[B]): B =
  39. ifEmpty(a)(v)(mb.zero)
  40. def unfoldlSum[S](seed: S)(f: S => Maybe[(S, F)]): F =
  41. unfoldlSumOpt(seed)(f) getOrElse zero
  42. def unfoldrSum[S](seed: S)(f: S => Maybe[(F, S)]): F =
  43. unfoldrSumOpt(seed)(f) getOrElse zero
  44. /** Every `Monoid` gives rise to a [[scalaz.Category]], for which
  45. * the type parameters are phantoms.
  46. *
  47. * @note `category.monoid` = `this`
  48. */
  49. final def category: Category[λ[(α, β) => F]] =
  50. new Category[λ[(α, β) => F]] with SemigroupCompose {
  51. def id[A] = zero
  52. }
  53. /**
  54. * A monoidal applicative functor, that implements `point` and `ap`
  55. * with the operations `zero` and `append` respectively. Note that
  56. * the type parameter `α` in `Applicative[λ[α => F]]` is
  57. * discarded; it is a phantom type. As such, the functor cannot
  58. * support [[scalaz.Bind]].
  59. */
  60. final def applicative: Applicative[λ[α =>F]] =
  61. new Applicative[λ[α => F]] with SemigroupApply {
  62. def point[A](a: => A) = zero
  63. }
  64. /**
  65. * Monoid instances must satisfy [[scalaz.Semigroup.SemigroupLaw]] and 2 additional laws:
  66. *
  67. * - '''left identity''': `forall a. append(zero, a) == a`
  68. * - '''right identity''' : `forall a. append(a, zero) == a`
  69. */
  70. trait MonoidLaw extends SemigroupLaw {
  71. def leftIdentity(a: F)(implicit F: Equal[F]): Boolean = F.equal(a, append(zero, a))
  72. def rightIdentity(a: F)(implicit F: Equal[F]): Boolean = F.equal(a, append(a, zero))
  73. }
  74. def monoidLaw = new MonoidLaw {}
  75. ////
  76. val monoidSyntax: scalaz.syntax.MonoidSyntax[F] =
  77. new scalaz.syntax.MonoidSyntax[F] { def F = Monoid.this }
  78. }
  79. object Monoid {
  80. @inline def apply[F](implicit F: Monoid[F]): Monoid[F] = F
  81. import Isomorphism._
  82. def fromIso[F, G](D: F <=> G)(implicit M: Monoid[G]): Monoid[F] =
  83. new IsomorphismMonoid[F, G] {
  84. override def G: Monoid[G] = M
  85. override def iso: F <=> G = D
  86. }
  87. ////
  88. /** Make an append and zero into an instance. */
  89. def instance[A](f: (A, => A) => A, z: A): Monoid[A] =
  90. new Monoid[A] {
  91. def zero = z
  92. def append(f1: A, f2: => A): A = f(f1,f2)
  93. }
  94. private trait ApplicativeMonoid[F[_], M] extends Monoid[F[M]] with Semigroup.ApplySemigroup[F, M] {
  95. implicit def F: Applicative[F]
  96. implicit def M: Monoid[M]
  97. val zero = F.point(M.zero)
  98. }
  99. /**A monoid for sequencing Applicative effects. */
  100. def liftMonoid[F[_], M](implicit F0: Applicative[F], M0: Monoid[M]): Monoid[F[M]] =
  101. new ApplicativeMonoid[F, M] {
  102. implicit def F: Applicative[F] = F0
  103. implicit def M: Monoid[M] = M0
  104. }
  105. def liftPlusEmpty[A](implicit M0: Monoid[A]): PlusEmpty[λ[α => A]] =
  106. new PlusEmpty[λ[α => A]] {
  107. type A0[α] = A
  108. def empty[A]: A0[A] = M0.zero
  109. def plus[A](f1: A0[A], f2: => A0[A]): A0[A] = M0.append(f1, f2)
  110. }
  111. /** Monoid is an invariant functor. */
  112. implicit val monoidInvariantFunctor: InvariantFunctor[Monoid] =
  113. new InvariantFunctor[Monoid] {
  114. def xmap[A, B](ma: Monoid[A], f: A => B, g: B => A): Monoid[B] = new Monoid[B] {
  115. def zero: B = f(ma.zero)
  116. def append(x: B, y: => B): B = f(ma.append(g(x), g(y)))
  117. }
  118. }
  119. ////
  120. }
  121. trait IsomorphismMonoid[F, G] extends Monoid[F] with IsomorphismSemigroup[F, G]{
  122. implicit def G: Monoid[G]
  123. ////
  124. def zero: F = iso.from(G.zero)
  125. ////
  126. }