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

scalaz.Contravariant.scala Maven / Gradle / Ivy

The newest version!
package scalaz

////
import scalaz.Liskov.<~<
/**
 * Contravariant functors.  For example, functions provide a
 * [[scalaz.Functor]] in their result type, but a
 * [[scalaz.Contravariant]] for each argument type.
 *
 * Note that the dual of a [[scalaz.Functor]] is just a [[scalaz.Functor]]
 * itself.
 *
 * Providing an instance of this is a useful alternative to marking a
 * type parameter with `-` in Scala.
 *
 * @see [[scalaz.Contravariant.ContravariantLaw]]
 */
////
trait Contravariant[F[_]] extends InvariantFunctor[F] { self =>
  ////

  /** Transform `A`.
    *
    * @note `contramap(r)(identity)` = `r`
    */
  def contramap[A, B](r: F[A])(f: B => A): F[B]

  // derived functions

  def narrow[A, B](fa: F[A])(implicit ev: B <~< A): F[B] =
    contramap(fa)(ev.apply)

  def xmap[A, B](fa: F[A], f: A => B, g: B => A): F[B] =
    contramap(fa)(g)

  /** The composition of Contravariant F and G, `[x]F[G[x]]`, is
    * covariant.
    */
  def compose[G[_]](implicit G0: Contravariant[G]): Functor[λ[α => F[G[α]]]] =
    new Functor[λ[α => F[G[α]]]] {
      def map[A, B](fa: F[G[A]])(f: A => B) =
        self.contramap(fa)(gb => G0.contramap(gb)(f))
    }

  /** The composition of Contravariant F and Functor G, `[x]F[G[x]]`,
    * is contravariant.
    */
  def icompose[G[_]](implicit G0: Functor[G]): Contravariant[λ[α => F[G[α]]]] =
    new Contravariant[λ[α => F[G[α]]]] {
      def contramap[A, B](fa: F[G[A]])(f: B => A) =
        self.contramap(fa)(G0.lift(f))
    }

  /** The product of Contravariant `F` and `G`, `[x](F[x], G[x]])`, is
    * contravariant.
    */
  def product[G[_]](implicit G0: Contravariant[G]): Contravariant[λ[α => (F[α], G[α])]] =
    new Contravariant[λ[α => (F[α], G[α])]] {
      def contramap[A, B](fa: (F[A], G[A]))(f: B => A) =
        (self.contramap(fa._1)(f), G0.contramap(fa._2)(f))
    }

  trait ContravariantLaw extends InvariantFunctorLaw {
    /** The identity function, lifted, is a no-op. */
    def identity[A](fa: F[A])(implicit FA: Equal[F[A]]): Boolean = FA.equal(contramap(fa)(x => x), fa)

    /**
     * A series of contramaps may be freely rewritten as a single
     * contramap on a composed function.
     */
    def composite[A, B, C](fa: F[A], f1: B => A, f2: C => B)(implicit FC: Equal[F[C]]): Boolean = FC.equal(contramap(contramap(fa)(f1))(f2), contramap(fa)(f1 compose f2))
  }
  def contravariantLaw: ContravariantLaw = new ContravariantLaw {}

  ////
  val contravariantSyntax: scalaz.syntax.ContravariantSyntax[F] =
    new scalaz.syntax.ContravariantSyntax[F] { def F = Contravariant.this }
}

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

  import Isomorphism._

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

  ////

  ////
}

trait IsomorphismContravariant[F[_], G[_]] extends Contravariant[F] with IsomorphismInvariantFunctor[F, G]{
  implicit def G: Contravariant[G]
  ////
  import Isomorphism._

  def iso: F <~> G

  override def contramap[A, B](r: F[A])(f: B => A): F[B] =
    iso.from(G.contramap(iso.to(r))(f))
  ////
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy