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 = new (E ~> G) {
    def apply[A](ea: E[A]) = self(f(ea))
  }

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

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 = 
    new (Id ~> Id) {
      def apply[A](a: A) = a
    }

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

  /** Reify a `NaturalTransformation`. */
  implicit def natToFunction[F[_], G[_], A](f: F ~> G): F[A] => G[A] = x => f(x)
}

object NaturalTransformation extends NaturalTransformations

/** 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