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

scalaz.Coyoneda.scala Maven / Gradle / Ivy

The newest version!
package scalaz

/**
 * The dual view of the Yoneda lemma. Also a free functor on `F`.
 * This is isomorphic to `F` as long as `F` itself is a functor.
 * The homomorphism from `F[A]` to `Coyoneda[F,A]` exists even when
 * `F` is not a functor.
 */
sealed abstract class Coyoneda[F[_], A] { coyo =>
  /** The pivot between `fi` and `k`, usually existential. */
  type I

  /** The underlying value. */
  val fi: F[I]

  /** The transformer function, to be lifted into `F` by `run`. */
  val k: I => A

  import Coyoneda.{Aux, apply}

  /** Converts to `F[A]` given that `F` is a functor */
  final def run(implicit F: Functor[F]): F[A] =
    F.map(fi)(k)

  /** Alias for `run`. */
  @inline final def unlift(implicit F: Functor[F]): F[A] = run

  /** Converts to `Yoneda[F,A]` given that `F` is a functor */
  final def toYoneda(implicit F: Functor[F]): Yoneda[F, A] = new Yoneda[F, A] {
    def apply[B](f: A => B) = F.map(fi)(k andThen f)
  }

  /** Simple function composition. Allows map fusion without touching
    * the underlying `F`.
    */
  final def map[B](f: A => B): Aux[F, B, I] =
    apply(fi)(f compose k)

  final def trans[G[_]](f: F ~> G): Aux[G, A, I] =
    apply(f(fi))(k)

  import Id._

  /** `Coyoneda[F,_]` is the left Kan extension of `F` along `Id` */
  def toLan: Lan[Id, F, A] = new Lan[Id, F, A] {
    type I = coyo.I
    val v: F[I] = fi
    def f(i: I) = k(i)
  }

  /** `Coyoneda` is a monad in an endofunctor category */
  def flatMap[G[_]](f: F ~> Coyoneda[G,*]): Coyoneda[G,A] =
    f(fi).map(k)

  /** `Coyoneda` is a comonad in an endofunctor category */
  def extend[G[_]](f: Coyoneda[F,*] ~> G): Coyoneda[G,A] =
    Coyoneda.lift(f(this))
}

object Coyoneda extends CoyonedaInstances {
  /** Lift the `I` type member to a parameter.  It is usually more
    * convenient to use `Aux` than a structural type.
    */
  type Aux[F[_], A, B] = Coyoneda[F, A] {type I = B}

  /** `F[A]` converts to `Coyoneda[F,A]` for any `F` */
  def lift[F[_],A](fa: F[A]): Coyoneda[F, A] = apply(fa)(identity[A])

  /** See `by` method. */
  final class By[F[_]] {
    @inline def apply[A, B](k: A => B)(implicit F: F[A]): Aux[F, B, A] =
      Coyoneda(F)(k)
  }

  /** Partial application of type parameters to `apply`.  It is often
    * more convenient to invoke `Coyoneda.by[F]{x: X => ...}` then
    * `Coyoneda[...](...){x => ...}`.
    */
  @inline def by[F[_]]: By[F] = new By[F]

  /** Like `lift(fa).map(_k)`. */
  def apply[F[_], A, B](fa: F[A])(_k: A => B): Aux[F, B, A] =
    new Coyoneda[F, B]{
      type I = A
      val k = _k
      val fi = fa
    }

  import Isomorphism._

  def iso[F[_]: Functor]: Coyoneda[F, *] <~> F =
    new IsoFunctorTemplate[Coyoneda[F, *], F] {
      def from_[A](fa: F[A]) = lift(fa)
      def to_[A](fa: Coyoneda[F, A]) = fa.run
    }

  /** Turns a natural transformation F ~> G into CF ~> G */
  def liftTF[F[_], G[_]: Functor](fg: F ~> G): Coyoneda[F, *] ~> G = {
    type CF[A] = Coyoneda[F, A]
    type CG[A] = Coyoneda[G, A]
    val m: (CF ~> CG) = liftT(fg)
    val n: (CG ~> G) = iso[G].to
    n compose m
  }

  /** Turns a natural transformation F ~> G into CF ~> CG */
  def liftT[F[_], G[_]](fg: F ~> G): Coyoneda[F, *] ~> Coyoneda[G, *] =
    new (Coyoneda[F, *] ~> Coyoneda[G, *]) {
      def apply[A](c: Coyoneda[F, A]): Coyoneda[G, A] = c.trans(fg)
    }

}

sealed abstract class CoyonedaInstances extends CoyonedaInstances0 {
  implicit def coyonedaOrder[A, F[_]](implicit A: Order[F[A]], F: Functor[F]): Order[Coyoneda[F, A]] =
    new IsomorphismOrder[Coyoneda[F, A], F[A]] {
      def G = A
      def iso = Coyoneda.iso[F].unlift
    }

  implicit def coyonedaBindRec[F[_]: BindRec]: BindRec[Coyoneda[F, *]] =
    new IsomorphismBindRec[Coyoneda[F, *], F] with CoyonedaFunctor[F] {
      def G = implicitly
      def iso = Coyoneda.iso
    }
}

sealed abstract class CoyonedaInstances0 extends CoyonedaInstances1 {
  implicit def coyonedaComonad[F[_]: Comonad]: Comonad[Coyoneda[F, *]] =
    new IsomorphismComonad[Coyoneda[F, *], F] with CoyonedaFunctor[F] {
      def G = implicitly
      def iso = Coyoneda.iso
    }
}

sealed abstract class CoyonedaInstances1 extends CoyonedaInstances2 {
  implicit def coyonedaEqual[A, F[_]](implicit A: Equal[F[A]], F: Functor[F]): Equal[Coyoneda[F, A]] =
    new IsomorphismEqual[Coyoneda[F, A], F[A]] {
      def G = A
      def iso = Coyoneda.iso[F].unlift
    }

  implicit def coyonedaCobind[F[_]: Cobind]: Cobind[Coyoneda[F, *]] =
    new IsomorphismCobind[Coyoneda[F, *], F] with CoyonedaFunctor[F] {
      def G = implicitly
      def iso = Coyoneda.iso
    }
}

sealed abstract class CoyonedaInstances2 extends CoyonedaInstances3 {
  implicit def coyonedaTraverse1[F[_]: Traverse1]: Traverse1[Coyoneda[F, *]] =
    new IsomorphismTraverse1[Coyoneda[F, *], F] with CoyonedaFunctor[F] {
      def G = implicitly
      def iso = Coyoneda.iso
    }
}

sealed abstract class CoyonedaInstances3 extends CoyonedaInstances4 {
  implicit def coyonedaMonadPlus[F[_]: MonadPlus]: MonadPlus[Coyoneda[F, *]] =
    new IsomorphismMonadPlus[Coyoneda[F, *], F] with CoyonedaBind[F] {
      override def G: MonadPlus[F] = MonadPlus[F]
      def iso = Coyoneda.iso
    }
}

sealed abstract class CoyonedaInstances4 extends CoyonedaInstances5 {
  implicit def coyonedaApplicativePlus[F[_]: ApplicativePlus]: ApplicativePlus[Coyoneda[F, *]] =
    new IsomorphismApplicativePlus[Coyoneda[F, *], F] with CoyonedaFunctor[F] {
      def G = implicitly
      def iso = Coyoneda.iso
    }
}

sealed abstract class CoyonedaInstances5 extends CoyonedaInstances6 {
  implicit def coyonedaMonad[F[_]: Monad]: Monad[Coyoneda[F, *]] =
    new IsomorphismMonad[Coyoneda[F, *], F] with CoyonedaBind[F] {
      override def G: Monad[F] = Monad[F]
      def iso = Coyoneda.iso
    }

  implicit def coyonedaPlusEmpty[F[_]: PlusEmpty: Functor]: PlusEmpty[Coyoneda[F, *]] =
    new IsomorphismPlusEmpty[Coyoneda[F, *], F] {
      def G = implicitly
      def iso = Coyoneda.iso
    }
}

sealed abstract class CoyonedaInstances6 extends CoyonedaInstances7 {
  implicit def coyonedaBind[F[_]: Bind]: Bind[Coyoneda[F, *]] =
    new CoyonedaBind[F] {
      def G = implicitly
    }

  implicit def coyonedaPlus[F[_]: Plus: Functor]: Plus[Coyoneda[F, *]] =
    new IsomorphismPlus[Coyoneda[F, *], F] {
      def G = implicitly
      def iso = Coyoneda.iso
    }
}

private trait CoyonedaBind[F[_]] extends Bind[Coyoneda[F, *]] with CoyonedaFunctor[F] {
  implicit def G: Bind[F]
  override def bind[A, B](fa: Coyoneda[F,A])(f: A => Coyoneda[F,B]): Coyoneda[F,B] =
    Coyoneda.lift(G.bind(fa.fi) { i =>
      f(fa.k(i)).unlift
    })
}

sealed abstract class CoyonedaInstances7 extends CoyonedaInstances8 {
  implicit def coyonedaApplicative[F[_]: Applicative]: Applicative[Coyoneda[F, *]] =
    new IsomorphismApplicative[Coyoneda[F, *], F] with CoyonedaFunctor[F] {
      def G = implicitly
      def iso = Coyoneda.iso
    }
}

sealed abstract class CoyonedaInstances8 extends CoyonedaInstances9 {
  implicit def coyonedaFoldable1[F[_]: Foldable1]: Foldable1[Coyoneda[F, *]] =
    new CoyonedaFoldable1[F]{ def F = implicitly }

  implicit def coyonedaApply[F[_]: Apply]: Apply[Coyoneda[F, *]] =
    new IsomorphismApply[Coyoneda[F, *], F] with CoyonedaFunctor[F] {
      def G = implicitly
      def iso = Coyoneda.iso
    }
}

sealed abstract class CoyonedaInstances9 extends CoyonedaInstances10 {
  implicit def coyonedaTraverse[F[_]: Traverse]: Traverse[Coyoneda[F, *]] =
    new IsomorphismTraverse[Coyoneda[F, *], F] with CoyonedaFunctor[F] {
      def G = implicitly
      def iso = Coyoneda.iso
    }

  implicit def coyonedaContravariant[F[_]: Contravariant: Functor]: Contravariant[Coyoneda[F, *]] =
    new IsomorphismContravariant[Coyoneda[F, *], F] {
      def G = implicitly
      def iso = Coyoneda.iso
    }
}

sealed abstract class CoyonedaInstances10 extends CoyonedaInstances11 {
  implicit def coyonedaFoldable[F[_]: Foldable]: Foldable[Coyoneda[F, *]] =
    new CoyonedaFoldable[F]{ def F = implicitly }

  /** `Coyoneda[F,_]` is a functor for any `F` */
  implicit def coyonedaFunctor[F[_]]: Functor[Coyoneda[F, *]] =
    new CoyonedaFunctor[F] {}
}

sealed abstract class CoyonedaInstances11 extends CoyonedaInstances12 {
  implicit def coyonedaNondeterminism[F[_]: Nondeterminism]: Nondeterminism[Coyoneda[F, *]] =
    new IsomorphismNondeterminism[Coyoneda[F, *], F] with CoyonedaBind[F] {
      override def G: Nondeterminism[F] = Nondeterminism[F]
      def iso = Coyoneda.iso
    }
}

sealed abstract class CoyonedaInstances12 {
  implicit def coyonedaMonadError[S, F[_]](implicit F: MonadError[F, S]): MonadError[Coyoneda[F, *], S] =
    new IsomorphismMonadError[Coyoneda[F, *], F, S] with CoyonedaBind[F] {
      override def G: MonadError[F, S] = F
      def iso = Coyoneda.iso
    }

}

private trait CoyonedaFunctor[F[_]] extends Functor[Coyoneda[F, *]] {
  override def map[A, B](ya: Coyoneda[F, A])(f: A => B): Coyoneda[F, B] = ya map f
}

private trait CoyonedaFoldable[F[_]] extends Foldable[Coyoneda[F, *]] {
  def F: Foldable[F]

  override final def foldMap[A, B: Monoid](fa: Coyoneda[F, A])(f: A => B) =
    F.foldMap(fa.fi)(fa.k andThen f)
  override final def foldRight[A, B](fa: Coyoneda[F, A], z: => B)(f: (A, => B) => B) =
    F.foldRight(fa.fi, z)((i, b) => f(fa.k(i), b))
  override final def foldLeft[A, B](fa: Coyoneda[F, A], z: B)(f: (B, A) => B) =
    F.foldLeft(fa.fi, z)((b, i) => f(b, fa.k(i)))
}

private abstract class CoyonedaFoldable1[F[_]] extends Foldable1[Coyoneda[F, *]] with CoyonedaFoldable[F] {
  def F: Foldable1[F]

  override final def foldMap1[A, B: Semigroup](fa: Coyoneda[F, A])(f: A => B) =
    F.foldMap1(fa.fi)(fa.k andThen f)
  override final def foldMapRight1[A, B](fa: Coyoneda[F, A])(z: A => B)(f: (A, => B) => B) =
    F.foldMapRight1(fa.fi)(i => z(fa.k(i)))((i, b) => f(fa.k(i), b))
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy