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