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

cats.free.Coyoneda.scala Maven / Gradle / Ivy

The newest version!
package cats
package free

/**
 * 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] extends Serializable { self =>

  /** The pivot between `fi` and `k`, usually existential. */
  type Pivot

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

  /** The transformer function, to be lifted into `F` by `run`. */
  val k: Pivot => 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)

  /** 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[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, Pivot] =
    apply(fi)(f compose k)

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

}

object Coyoneda {
  /** Lift the `Pivot` 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 Pivot = 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])

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

  /**
   * As the free functor, `Coyoneda[F, ?]` provides a functor for any `F`.
   */
  implicit def coyonedaFunctor[F[_]]: Functor[Coyoneda[F, ?]] =
    new Functor[Coyoneda[F, ?]] {
      def map[A, B](cfa: Coyoneda[F, A])(f: A => B): Coyoneda[F, B] = cfa map f
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy