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

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

The newest version!
package cats
package free

/**
 * The free functor generated by `F`. The Yoneda lemma says that
 * `Yoneda[F,A]` is isomorphic to `F[A]` for any functor `F`.
 * The homomorphism from `Yoneda[F,A]` to `F[A]` exists even when
 * we have forgotten that `F` is a functor.
 * Can be seen as a partially applied `map` for the functor `F`.
 */
abstract class Yoneda[F[_], A] extends Serializable { self =>
  def apply[B](f: A => B): F[B]

  /**
   * Converts to `F[A]` even without a `Functor` instance for `F`
   */
  def run: F[A] = apply(a => a)

  /**
   * Converts to `Coyoneda[F,A]` even without a `Functor` instance for `F`
   */
  def toCoyoneda: Coyoneda.Aux[F, A, A] = Coyoneda(run)(identity[A])

  /**
   * Simple function composition. Allows map fusion without traversing an `F`.
   */
  def map[B](f: A => B): Yoneda[F, B] =
    new Yoneda[F, B] {
      def apply[C](g: B => C): F[C] = self(f andThen g)
    }

  // import Id._
  // /** `Yoneda[F, _]` is the right Kan extension of `F` along `Id` */
  // def toRan: Ran[Id, F, A] =
  //   new Ran[Id, F, A] {
  //     def apply[B](f: A => B) = self(f)
  //   }
}

object Yoneda {

  /**
   * `Yoneda[F, _]` is a functor for any `F`
   */
  implicit def yonedaFunctor[F[_]]: Functor[Yoneda[F, ?]] =
    new Functor[Yoneda[F, ?]] {
      def map[A, B](ya: Yoneda[F,A])(f: A => B): Yoneda[F, B] = ya map f
    }

  /**
   * `F[A]` converts to `Yoneda[F, A]` for any functor `F`.
   */
  def apply[F[_], A](fa: F[A])(implicit F: Functor[F]): Yoneda[F, A] =
    new Yoneda[F, A] {
      def apply[B](f: A => B): F[B] = F.map(fa)(f)
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy