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

scalaz.Inject.scala Maven / Gradle / Ivy

package scalaz

import std.option.{none, some}

/**
 * Inject type class as described in "Data types a la carte" (Swierstra 2008).
 *
 * @see [[http://www.staff.science.uu.nl/~swier004/Publications/DataTypesALaCarte.pdf]]
 */
sealed abstract class Inject[F[_], G[_]] extends (F ~> G) {
  def apply[A](fa: F[A]): G[A] = inj(fa)
  def unapply[A](ga: G[A]): Option[F[A]] = prj(ga)
  def inj[A](fa: F[A]): G[A]
  def prj[A](ga: G[A]): Option[F[A]]
}

sealed abstract class InjectInstances {
  implicit def reflexiveInjectInstance[F[_]]: Inject[F, F] =
    new Inject[F, F] {
      def inj[A](fa: F[A]) = fa
      def prj[A](ga: F[A]) = some(ga)
    }

  implicit def leftInjectInstance[F[_], G[_]]: Inject[F, Coproduct[F, G, *]]  =
    new Inject[F, Coproduct[F, G, *]] {
      def inj[A](fa: F[A]) = Coproduct.leftc(fa)
      def prj[A](ga: Coproduct[F, G, A]) = ga.run.fold(some, _ => none)
    }

  implicit def rightInjectInstance[F[_], G[_], H[_]](implicit I: Inject[F, G]): Inject[F, Coproduct[H, G, *]] =
      new Inject[F, Coproduct[H, G, *]] {
        def inj[A](fa: F[A]) = Coproduct.rightc(I.inj(fa))
        def prj[A](ga: Coproduct[H, G, A]) = ga.run.fold(_ => none, I.prj)
      }
}

object Inject extends InjectInstances {
  /**
   * This should only be used by third party coproduct encodings. If `G <:
   * Coproduct` it is likely to break typeclass coherence. Caveat Emptor.
   */
  def instance[F[_], G[_]](
    inj_ : F ~> G,
    prj_ : G ~> λ[α => Option[F[α]]]
  ): Inject[F, G] = new Inject[F, G] {
    override def inj[A](fa: F[A]): G[A] = inj_(fa)
    override def prj[A](ga: G[A]): Option[F[A]] = prj_(ga)
  }

  def inject[F[_], G[_], A](ga: G[Free[F, A]])(implicit I: Inject[G, F]): Free[F, A] =
    Free[F, A](I.inj(ga))

  def match_[F[_], G[_], A](fa: Free[F, A])(implicit F: Functor[F], I: Inject[G, F]): Option[G[Free[F, A]]] =
    fa.resume.fold(I.prj, _ => none)

  @inline def apply[F[_], G[_]](implicit I: Inject[F, G]): Inject[F, G] = I
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy