/core/src/main/scala/scalaz/Contravariant.scala
http://github.com/scalaz/scalaz · Scala · 106 lines · 47 code · 19 blank · 40 comment · 0 complexity · 217c625233716dcac308a5112d00f0bf MD5 · raw file
- 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 = 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))
- ////
- }