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

scalaz.Isomorphism.scala Maven / Gradle / Ivy

The newest version!
package scalaz

sealed abstract class Isomorphisms {

  /**Isomorphism for arrows of kind * -> * -> * */
  trait Iso[Arr[_, _], A, B] {
    self =>
    def to: Arr[A, B]
    def from: Arr[B, A]
    def flip: Iso[Arr, B, A] = new Iso[Arr, B, A] {
      val to = self.from
      val from = self.to
      override def flip = self
    }

    def %~(f: Arr[B, B])(implicit C: Compose[Arr]): Arr[A, A] =
      C.compose(from, C.compose(f, to))
  }

  /**Isomorphism for arrows of kind (* -> *) -> (* -> *) -> * */
  trait Iso2[Arr[_[_], _[_]], F[_], G[_]] {
    self =>
    def to: Arr[F, G]
    def from: Arr[G, F]
    def flip: Iso2[Arr, G, F] = new Iso2[Arr, G, F] {
      val to = self.from
      val from = self.to
      override def flip = self
    }

    import Liskov._

    def unlift[A](implicit FG: Arr[F, G] <~< (F ~> G), GF: Arr[G, F] <~< (G ~> F)): F[A] <=> G[A] =
      new (F[A] <=> G[A]){
        def from = GF(self.from).apply
        def to   = FG(self.to).apply
      }

    def %~(f: G ~> G)(implicit FG: Arr[F, G] <~< (F ~> G), GF: Arr[G, F] <~< (G ~> F)): F ~> F =
      new (F ~> F) {
        def apply[A](a: F[A]): F[A] = GF(self.from)(f(FG(self.to)(a)))
      }
  }

  /**Isomorphism for arrows of kind (* -> * -> *) -> (* -> * -> *) -> * */
  trait Iso3[Arr[_[_, _], _[_, _]], F[_, _], G[_, _]] {
    self =>
    def to: Arr[F, G]
    def from: Arr[G, F]
    def flip: Iso3[Arr, G, F] = new Iso3[Arr, G, F] {
      val to = self.from
      val from = self.to
      override def flip = self
    }

    import Liskov._

    def unlift[A, B](implicit
      FG: Arr[F, G] <~< (F ~~> G),
      GF: Arr[G, F] <~< (G ~~> F)
    ): F[A, B] <=> G[A, B] =
      new (F[A, B] <=> G[A, B]){
        def from = GF(self.from).apply
        def to   = FG(self.to).apply
      }

    def unlift1[A](implicit
      FG: Arr[F, G] <~< (F ~~> G),
      GF: Arr[G, F] <~< (G ~~> F)
    ): F[A, *] <~> G[A, *] = {
      type FA[α] = F[A, α]
      type GA[α] = G[A, α]
      new IsoFunctorTemplate[FA, GA]{
        def from_[X](ga: GA[X]) = GF(self.from)(ga)
        def to_[X](fa: FA[X]) = FG(self.to)(fa)
      }
    }

    def unlift2[A](implicit
      FG: Arr[F, G] <~< (F ~~> G),
      GF: Arr[G, F] <~< (G ~~> F)
    ): F[*, A] <~> G[*, A] = {
      type FA[α] = F[α, A]
      type GA[α] = G[α, A]
      new IsoFunctorTemplate[FA, GA]{
        def from_[X](ga: GA[X]) = GF(self.from)(ga)
        def to_[X](fa: FA[X]) = FG(self.to)(fa)
      }
    }

    def %~(f: G ~~> G)(implicit FG: Arr[F, G] <~< (F ~~> G), GF: Arr[G, F] <~< (G ~~> F)): F ~~> F =
      new (F ~~> F) {
        def apply[A, B](a: F[A, B]): F[A, B] = GF(self.from)(f(FG(self.to)(a)))
      }
  }

  /**Set isomorphism */
  type IsoSet[A, B] = Iso[Function1, A, B]

  /**Natural isomorphism between functors */
  type IsoFunctor[F[_], G[_]] = Iso2[NaturalTransformation, F, G]

  type IsoBifunctor[F[_, _], G[_, _]] = Iso3[~~>, F, G]

  /**Alias for IsoSet */
  type <=>[A, B] = IsoSet[A, B]

  object IsoSet {
    /**Convenience constructor to implement `A <=> B` from `A => B` and `B => A` */
    def apply[A, B](to: A => B, from: B => A): A <=> B = {
      val _to   = to
      val _from = from
      new Iso[Function1, A, B] {
        override val to   = _to
        override val from = _from
      }
    }
  }

  /**Alias for IsoFunctor */
  type <~>[F[_], G[_]] = IsoFunctor[F, G]

  /**Convenience template trait to implement `<~>` */
  trait IsoFunctorTemplate[F[_], G[_]] extends IsoFunctor[F, G] {
    override final val to: NaturalTransformation[F, G] = new (F ~> G) {
      def apply[A](fa: F[A]): G[A] = to_[A](fa)
    }
    override final val from: NaturalTransformation[G, F] = new (G ~> F) {
      def apply[A](ga: G[A]): F[A] = from_[A](ga)
    }

    def to_[A](fa: F[A]): G[A]
    def from_[A](ga: G[A]): F[A]
  }

  object IsoFunctor {
    /**Convenience constructor to implement `F <~> G` from F ~> G and G ~> F */
    def apply[F[_], G[_]](to: F ~> G, from: G ~> F): F <~> G = {
      val _to   = to
      val _from = from
      new (F <~> G) {
        override val to = _to
        override val from = _from
      }
    }
  }

  /**Alias for IsoBifunctor */
  type <~~>[F[_, _], G[_, _]] = IsoBifunctor[F, G]

  /**Convenience template trait to implement `<~~>` */
  trait IsoBifunctorTemplate[F[_, _], G[_, _]] extends IsoBifunctor[F, G] {
    final val to: BiNaturalTransformation[F, G] = new (F ~~> G) {
      def apply[A, B](fab: F[A, B]): G[A, B] = to_[A, B](fab)
    }
    final val from: BiNaturalTransformation[G, F] = new (G ~~> F) {
      def apply[A, B](gab: G[A, B]): F[A, B] = from_[A, B](gab)
    }

    def to_[A, B](fa: F[A, B]): G[A, B]
    def from_[A, B](ga: G[A, B]): F[A, B]
  }

  /**Set isomorphism is commutative */
  def commutative[A, B](i: A <=> B): B <=> A = i.flip

  /**Set isomorphism is reflexive */
  def refl[A]: A <=> A = new (A <=> A) {
    def to: A => A = a => a
    def from: A => A = a => a
  }

  /**Natural isomorphism is reflexive */
  def naturalRefl[F[_]]: F <~> F = new IsoFunctorTemplate[F, F] {
    def to_[A](fa: F[A]): F[A] = fa
    def from_[A](fa: F[A]): F[A] = fa
  }

  /**Natural isomorphism is commutative */
  def naturalCommutative[F[_], G[_]](i: F <~> G): G <~> F = i.flip

}

object Isomorphism extends Isomorphisms

import Isomorphism._

trait IsomorphismAssociative[F[_, _], G[_, _]] extends Associative[F] {
  implicit def G: Associative[G] & Bifunctor[G] // TODO: is this needed? (I think so)

  def iso: F <~~> G

  override def reassociateLeft[A, B, C](f: F[A, F[B, C]]): F[F[A, B], C] =
    iso.from(G.leftMap(G.reassociateLeft(G.rightMap(iso.to(f))(iso.to.apply)))(iso.from.apply))

  override def reassociateRight[A, B, C](f: F[F[A, B], C]): F[A, F[B, C]] =
    iso.from(G.rightMap(G.reassociateRight(G.leftMap(iso.to(f))(iso.to.apply)))(iso.from.apply))
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy