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

scalaz.NaturalTransformation.scala Maven / Gradle / Ivy

package scalaz

import Id._

/** A universally quantified function, usually written as `F ~> G`,
  * for symmetry with `A => B`.
  *
  * Can be used to encode first-class functor transformations in the
  * same way functions encode first-class concrete value morphisms;
  * for example, `sequence` from [[scalaz.Traverse]] and `cosequence`
  * from [[scalaz.Distributive]] give rise to `([a]T[A[a]]) ~>
  * ([a]A[T[a]])`, for varying `A` and `T` constraints.
  */
trait NaturalTransformation[F[_], G[_]] {
  self =>
  def apply[A](fa: F[A]): G[A]

  def compose[E[_]](f: E ~> F): E ~> G = λ[E ~> G](
    ea => self(f(ea))
  )

  def andThen[H[_]](f: G ~> H): F ~> H =
    f compose self

  /**
    * Combines this [[scalaz.NaturalTransformation]] with another one to create one
    * that can transform [[scalaz.Coproduct]].
    *
    * The current NaturalTransformation will be used to transform the Left (`F`) value of
    * the [[scalaz.Coproduct]] while the other one will be used to transform the Right (`H`) value.
    */
  def or[H[_]](hg: H ~> G): Coproduct[F, H, ?] ~> G =
    λ[Coproduct[F, H, ?] ~> G](_.fold(self, hg))

  import LiskovF._

  def widen[GG[_]](implicit ev: GG >~~> G): F ~> GG =
    ev.substCo[F ~> ?[_]](this)
  def narrow[FF[_]](implicit ev: FF <~~< F): FF ~> G =
    ev.substCt[?[_] ~> G](this)
}

trait NaturalTransformations {
  /** A function type encoded as a natural transformation by adding a
    * phantom parameter.
    */
  type ->[A, B] = λ[α => A] ~> λ[α => B]

  /** `refl` specialized to [[scalaz.Id.Id]]. */
  def id: Id ~> Id =
    λ[Id ~> Id](a => a)

  /** A universally quantified identity function */
  def refl[F[_]]: F ~> F =
    λ[F ~> F](fa => fa)
}

object NaturalTransformation extends NaturalTransformations {
  /**
   * Construct a natural transformation over a coproduct from its parts.
   * Useful for combining Free interpreters.
   */
  def or[F[_], G[_], H[_]](fg: F ~> G, hg: H ~> G): Coproduct[F, H, ?] ~> G =
    λ[Coproduct[F, H, ?] ~> G](_.fold(fg, hg))

  /**
   * Like Hoist, for Functors, when we already know how to transform `F ~> G`.
   */
  def liftMap[F[_], G[_], H[_]: Functor](in: F ~> G): λ[α => H[F[α]]] ~> λ[α => H[G[α]]] =
    λ[λ[α => H[F[α]]] ~> λ[α => H[G[α]]]](fa => Functor[H].map(fa)(in.apply))
}

/** A function universally quantified over two parameters. */
trait BiNaturalTransformation[-F[_, _], +G[_, _]] {
  self =>
  def apply[A, B](f: F[A, B]): G[A, B]

  def compose[E[_, _]](f: BiNaturalTransformation[E, F]) =
    new BiNaturalTransformation[E, G] {
      def apply[A, B](eab: E[A, B]): G[A, B] = self(f(eab))
    }
}

/** A constrained natural transformation */
trait ConstrainedNaturalTransformation[F[_], G[_], E[_]] {
  def apply[A: E](f: F[A]): G[A]
}

/** A constrained transformation natural in both sides of a bifunctor */
trait BiConstrainedNaturalTransformation[F[_,_], G[_,_], C[_], E[_]] {
  def apply[A: C, B: E](f: F[A,B]): G[A,B]
}

trait DiNaturalTransformation[F[_,_], G[_,_]] {
  def apply[A](f: F[A,A]): G[A,A]
}

// TODO needed, or just use type lambdas?
//type Thunk[A] = () => A
//
trait Konst[A] {
  type Apply[B] = A
}
//
//trait Biff[P[_,_], F[_], G[_]] {
//  type Apply[A, B] = P[F[A], G[B]]
//}
//
//trait On[P[_,_], F[_]] {
//  type Apply[A, B] = P[F[A], F[B]]
//}
//
//trait Distributes[F[_], G[_]] {
//  def apply[A](f: F[G[A]]): G[F[A]]
//}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy