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

scalaz.Bifunctor.scala Maven / Gradle / Ivy

The newest version!
package scalaz

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

  /** `map` over both type parameters. */
  def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D]

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

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

  /** Extract the Functor on the first param. */
  def leftFunctor[X]: Functor[F[*, X]] =
    new LeftFunctor[F, X] {val F = self}

  def leftMap[A, B, C](fab: F[A, B])(f: A => C): F[C, B] =
    bimap(fab)(f, z => z)

  /** Extract the Functor on the second param. */
  def rightFunctor[X]: Functor[F[X, *]] =
    new RightFunctor[F, X] {val F = self}

  /** Unify the functor over both params. */
  def uFunctor: Functor[λ[α => F[α, α]]] =
    new UFunctor[F] {val F = self}

  def rightMap[A, B, D](fab: F[A, B])(g: B => D): F[A, D] =
    bimap(fab)(z => z, g)

  def umap[A, B](faa: F[A, A])(f: A => B): F[B, B] =
    bimap(faa)(f, f)

  /** Embed two Functors , one on each side */
  def embed[G[_],H[_]](implicit G0: Functor[G], H0: Functor[H]): Bifunctor[λ[(α, β) => F[G[α],H[β]]]] =
    new CompositionBifunctorFunctors[F,G,H] {
      def F = self
      def G = G0
      def H = H0
    }

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

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

  /** Bifunctors are covariant by nature */
  def widen[A, B, C >: A, D >: B](fab: F[A, B]): F[C, D] =
    bimap(fab)(identity[C], identity[D])

  ////
  val bifunctorSyntax: scalaz.syntax.BifunctorSyntax[F] =
    new scalaz.syntax.BifunctorSyntax[F] { def F = Bifunctor.this }
}

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

  import Isomorphism._

  def fromIso[F[_, _], G[_, _]](D: F <~~> G)(implicit E: Bifunctor[G]): Bifunctor[F] =
    new IsomorphismBifunctor[F, G] {
      override def G: Bifunctor[G] = E
      override def iso: F <~~> G = D
    }

  ////

  ////
}

trait IsomorphismBifunctor[F[_, _], G[_, _]] extends Bifunctor[F] {
  implicit def G: Bifunctor[G]
  ////
  import Isomorphism._

  def iso: F <~~> G

  override def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D] =
    iso.from(G.bimap(iso.to(fab))(f, g))
  ////
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy