PageRenderTime 33ms CodeModel.GetById 2ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 1ms

/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}