/core/src/main/scala/scalaz/Plus.scala

http://github.com/scalaz/scalaz · Scala · 119 lines · 72 code · 24 blank · 23 comment · 0 complexity · d59b4d12a3d06e667d79a59bd3c7484a MD5 · raw file

  1. package scalaz
  2. ////
  3. import scala.annotation.tailrec
  4. import scalaz.Maybe.Just
  5. /**
  6. * Universally quantified [[scalaz.Semigroup]].
  7. */
  8. ////
  9. trait Plus[F[_]] { self =>
  10. ////
  11. def plus[A](a: F[A], b: => F[A]): F[A]
  12. /**
  13. * Unfold `seed` to the left and sum using [[#plus]].
  14. * `Plus` instances with right absorbing elements may override this method
  15. * to not unfold more than is necessary to determine the result.
  16. */
  17. def unfoldlPsumOpt[S, A](seed: S)(f: S => Maybe[(S, F[A])]): Maybe[F[A]] = {
  18. @tailrec def go(s: S, acc: F[A]): F[A] = f(s) match {
  19. case Just((s, fa)) => go(s, plus(fa, acc))
  20. case _ => acc
  21. }
  22. f(seed) map { case (s, a) => go(s, a) }
  23. }
  24. /**
  25. * Unfold `seed` to the right and sum using [[#plus]].
  26. * `Plus` instances with left absorbing elements may override this method
  27. * to not unfold more than is necessary to determine the result.
  28. */
  29. def unfoldrPsumOpt[S, A](seed: S)(f: S => Maybe[(F[A], S)]): Maybe[F[A]] = {
  30. @tailrec def go(acc: F[A], s: S): F[A] = f(s) match {
  31. case Just((fa, s)) => go(plus(acc, fa), s)
  32. case _ => acc
  33. }
  34. f(seed) map { case (a, s) => go(a, s) }
  35. }
  36. /**The composition of Plus `F` and `G`, `[x]F[G[x]]`, is a Plus */
  37. def compose[G[_]]: Plus[λ[α => F[G[α]]]] =
  38. new CompositionPlus[F, G] {
  39. implicit def F = self
  40. }
  41. /**The product of Plus `F` and `G`, `[x](F[x], G[x]])`, is a Plus */
  42. def product[G[_]](implicit G0: Plus[G]): Plus[λ[α => (F[α], G[α])]] =
  43. new ProductPlus[F, G] {
  44. implicit def F = self
  45. implicit def G = G0
  46. }
  47. def semigroup[A]: Semigroup[F[A]] = new Semigroup[F[A]] {
  48. def append(f1: F[A], f2: => F[A]): F[A] = plus(f1, f2)
  49. override def unfoldlSumOpt[S](seed: S)(f: S => Maybe[(S, F[A])]): Maybe[F[A]] =
  50. unfoldlPsumOpt(seed)(f)
  51. override def unfoldrSumOpt[S](seed: S)(f: S => Maybe[(F[A], S)]): Maybe[F[A]] =
  52. unfoldrPsumOpt(seed)(f)
  53. }
  54. trait PlusLaw {
  55. def associative[A](f1: F[A], f2: F[A], f3: F[A])(implicit FA: Equal[F[A]]): Boolean =
  56. FA.equal(plus(f1, plus(f2, f3)), plus(plus(f1, f2), f3))
  57. }
  58. def plusLaw =
  59. new PlusLaw {}
  60. ////
  61. val plusSyntax: scalaz.syntax.PlusSyntax[F] =
  62. new scalaz.syntax.PlusSyntax[F] { def F = Plus.this }
  63. }
  64. object Plus {
  65. @inline def apply[F[_]](implicit F: Plus[F]): Plus[F] = F
  66. import Isomorphism._
  67. def fromIso[F[_], G[_]](D: F <~> G)(implicit E: Plus[G]): Plus[F] =
  68. new IsomorphismPlus[F, G] {
  69. override def G: Plus[G] = E
  70. override def iso: F <~> G = D
  71. }
  72. ////
  73. private[scalaz] trait LiftedPlus[G[_], F[_]] extends Plus[λ[a => G[F[a]]]] {
  74. implicit def G: Apply[G]
  75. implicit def F: Plus[F]
  76. def plus[A](x: G[F[A]], y: => G[F[A]]): G[F[A]] = G.apply2(x, y)(F.plus(_, _))
  77. override def unfoldrPsumOpt[S, A](seed: S)(f: S => Maybe[(G[F[A]], S)]): Maybe[G[F[A]]] =
  78. G.unfoldrOpt(seed)(f)(Reducer.identityReducer[F[A]](F.semigroup))
  79. }
  80. def liftPlus[G[_], F[_]](implicit G0: Apply[G], F0: Plus[F]): Plus[λ[a => G[F[a]]]] =
  81. new LiftedPlus[G, F] {
  82. def G = G0
  83. def F = F0
  84. }
  85. ////
  86. }
  87. trait IsomorphismPlus[F[_], G[_]] extends Plus[F] {
  88. implicit def G: Plus[G]
  89. ////
  90. import Isomorphism._
  91. def iso: F <~> G
  92. def plus[A](a: F[A], b: => F[A]): F[A] =
  93. iso.from(G.plus(iso.to(a), iso.to(b)))
  94. ////
  95. }