All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scalaz.Bifoldable.scala Maven / Gradle / Ivy

The newest version!
package scalaz

////
/**
 * A type giving rise to two unrelated [[scalaz.Foldable]]s.
 */
////
trait Bifoldable[F[_, _]]  { self =>
  ////

  /** Accumulate `A`s and `B`s */
  def bifoldMap[A,B,M](fa: F[A, B])(f: A => M)(g: B => M)(implicit F: Monoid[M]): M

  /** Accumulate to `C` starting at the "right".  `f` and `g` may be
    * interleaved.
    */
  def bifoldRight[A,B,C](fa: F[A, B], z: => C)(f: (A, => C) => C)(g: (B, => C) => C): C

  // derived functions

  /** `bifoldRight`, but defined to run in the opposite direction. */
  def bifoldLeft[A,B,C](fa: F[A, B], z: C)(f: (C, A) => C)(g: (C, B) => C): C = {
    import Dual._, Endo._, syntax.std.all._
    Tag.unwrap(bifoldMap(fa)((a: A) => Dual(Endo.endo(f.flip.curried(a))))((b: B) => Dual(Endo.endo(g.flip.curried(b))))(dualMonoid[Endo[C]])) apply z
  }

  /**The composition of Bifoldables `F` and `G`, `[x,y]F[G[x,y],G[x,y]]`, is a Bifoldable */
  def compose[G[_, _]](implicit G0: Bifoldable[G]): Bifoldable[λ[(α, β) => F[G[α, β], G[α, β]]]] =
    new CompositionBifoldable[F, G] {
      override def F = self
      override def G = G0
    }

  /**The product of Bifoldables `F` and `G`, `[x,y](F[x,y], G[x,y])`, is a Bifoldable */
  def product[G[_, _]](implicit G0: Bifoldable[G]): Bifoldable[λ[(α, β) => (F[α, β], G[α, β])]] =
    new ProductBifoldable[F, G] {
      override def F = self
      override def G = G0
    }

  // derived functions
  def bifoldMap1[A,B,M](fa: F[A,B])(f: A => M)(g: B => M)(implicit F: Semigroup[M]): Option[M] = {
    import std.option._
    bifoldMap(fa)(a => some(f(a)))(b => some(g(b)))
  }

  /**Curried version of `bifoldRight` */
  final def bifoldR[A, B, C](fa: F[A, B], z: => C)(f: A => (=> C) => C)(g: B => (=> C) => C): C =
    bifoldRight(fa, z)((a, c) => f(a)(c))((b, c) => g(b)(c))

  /**Curried version of `bifoldLeft` */
  final def bifoldL[A, B, C](fa: F[A, B], z: C)(f: C => A => C)(g: C => B => C): C =
    bifoldLeft(fa, z)(Function.uncurried(f))(Function.uncurried(g))

  /** Extract the Foldable on the first parameter. */
  def leftFoldable[X]: Foldable[F[*, X]] =
    new LeftFoldable[F, X] {val F = self}

  /** Extract the Foldable on the second parameter. */
  def rightFoldable[X]: Foldable[F[X, *]] =
    new RightFoldable[F, X] {val F = self}

  /** Unify the foldable over both params. */
  def uFoldable: Foldable[λ[α => F[α, α]]] =
    new UFoldable[F] {val F = self}

  /** Embed one Foldable at each side of this Bifoldable */
  def embed[G[_],H[_]](implicit G0: Foldable[G], H0: Foldable[H]): Bifoldable[λ[(α, β) => F[G[α],H[β]]]] =
    new CompositionBifoldableFoldables[F,G,H] {
      def F = self
      def G = G0
      def H = H0
    }

  /** Embed one Foldable to the left of this Bifoldable .*/
  def embedLeft[G[_]](implicit G0: Foldable[G]): Bifoldable[λ[(α, β) => F[G[α],β]]] =
    embed[G,Id.Id]

  /** Embed one Foldable to the right of this Bifoldable .*/
  def embedRight[H[_]](implicit H0: Foldable[H]): Bifoldable[λ[(α, β) => F[α,H[β]]]] =
    embed[Id.Id,H]

  trait BifoldableLaw {
    import std.vector._
    import syntax.either._

    def leftFMConsistent[A: Equal, B: Equal](fa: F[A, B]): Boolean =
      Equal[Vector[B \/ A]].equal(bifoldMap[A, B, Vector[B \/ A]](fa)(a => Vector(\/-(a)))(b => Vector(-\/(b))),
                                  bifoldLeft(fa, Vector.empty[B \/ A])(_ :+ \/-(_))(_ :+ -\/(_)))

    def rightFMConsistent[A: Equal, B: Equal](fa: F[A, B]): Boolean =
      Equal[Vector[B \/ A]].equal(bifoldMap[A, B, Vector[B \/ A]](fa)(a => Vector(\/-(a)))(b => Vector(-\/(b))),
                                  bifoldRight(fa, Vector.empty[B \/ A])(_.right[B] +: _)(_.left[A] +: _))
  }

  def bifoldableLaw: BifoldableLaw = new BifoldableLaw {}
  ////
  val bifoldableSyntax: scalaz.syntax.BifoldableSyntax[F] =
    new scalaz.syntax.BifoldableSyntax[F] { def F = Bifoldable.this }
}

object Bifoldable {
  @inline def apply[F[_, _]](implicit F: Bifoldable[F]): Bifoldable[F] = F



  ////

  def fromIso[F[_, _], G[_, _]](D: F ~~> G)(implicit E: Bifoldable[G]): Bifoldable[F] =
    new IsomorphismBifoldable[F, G] {
      override def G: Bifoldable[G] = E
      override def biNaturalTrans: F ~~> G = D
    }

  /**
   * Template trait to define `Bifoldable` in terms of `bifoldMap`.
   */
  trait FromBifoldMap[F[_, _]] extends Bifoldable[F] {
    override def bifoldRight[A,B,C](fa: F[A, B], z: => C)(f: (A, => C) => C)(g: (B, => C) => C) =
      bifoldMap(fa)((a: A) => Endo.endoByName[C](f(a, _)))((b: B) => Endo.endoByName[C](g(b, _))) apply z
  }

  /**
   * Template trait to define `Bifoldable` in terms of `bifoldR`
   */
  trait FromBifoldr[F[_, _]] extends Bifoldable[F] {
    override def bifoldMap[A, B, M](fa: F[A, B])(f: A => M)(g: B => M)(implicit F: Monoid[M]) =
      bifoldR(fa, F.zero)(x => y => F.append(f(x),  y))(x => y => F.append(g(x),  y))
  }

  ////
}

trait IsomorphismBifoldable[F[_, _], G[_, _]] extends Bifoldable[F] {
  implicit def G: Bifoldable[G]
  ////

  protected[this] def biNaturalTrans: F ~~> G

  override def bifoldMap[A, B, M: Monoid](fab: F[A, B])(f: A => M)(g: B => M): M =
    G.bifoldMap(biNaturalTrans(fab))(f)(g)

  override def bifoldRight[A, B, C](fab: F[A, B], z: => C)(f: (A, => C) => C)(g: (B, => C) => C): C =
    G.bifoldRight(biNaturalTrans(fab), z)(f)(g)

  override def bifoldLeft[A, B, C](fa: F[A, B], z: C)(f: (C, A) => C)(g: (C, B) => C): C =
    G.bifoldLeft(biNaturalTrans(fa), z)(f)(g)
  ////
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy