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

cats.InjectK.scala Maven / Gradle / Ivy

The newest version!
package cats

import cats.arrow.FunctionK
import cats.data.EitherK

/**
 * InjectK is a type class providing an injection from type
 * constructor `F` into type constructor `G`. An injection is a
 * functor transformation `inj` which does not destroy any
 * information: for every `ga: G[A]` there is at most one `fa: F[A]`
 * such that `inj(fa) = ga`.
 *
 * Because of this all injections admit partial inverses `prj` which
 * pair a value `ga: G[A]` back with a single value `fa: F[A]`.
 *
 * The behavior of the default instances for the InjectK type class
 * are described thoroughly in "Data types a la carte" (Swierstra
 * 2008).
 *
 * @note Prior to cats 1.0, InjectK was known as [[Inject]].
 *
 * @see [[http://www.staff.science.uu.nl/~swier004/publications/2008-jfp.pdf]]
 * @see [[Inject]] for injection for `Either`
 */
abstract class InjectK[F[_], G[_]] {
  def inj: FunctionK[F, G]

  def prj: FunctionK[G, λ[α => Option[F[α]]]]

  final def apply[A](fa: F[A]): G[A] = inj(fa)

  final def unapply[A](ga: G[A]): Option[F[A]] = prj(ga)
}

sealed abstract private[cats] class InjectKInstances {
  implicit def catsReflexiveInjectKInstance[F[_]]: InjectK[F, F] =
    new InjectK[F, F] {
      val inj = FunctionK.id[F]

      val prj = λ[FunctionK[F, λ[α => Option[F[α]]]]](Some(_))
    }

  implicit def catsLeftInjectKInstance[F[_], G[_]]: InjectK[F, EitherK[F, G, *]] =
    new InjectK[F, EitherK[F, G, *]] {
      val inj = λ[FunctionK[F, EitherK[F, G, *]]](EitherK.leftc(_))

      val prj = λ[FunctionK[EitherK[F, G, *], λ[α => Option[F[α]]]]](_.run.left.toOption)
    }

  implicit def catsRightInjectKInstance[F[_], G[_], H[_]](implicit I: InjectK[F, G]): InjectK[F, EitherK[H, G, *]] =
    new InjectK[F, EitherK[H, G, *]] {
      val inj = λ[FunctionK[G, EitherK[H, G, *]]](EitherK.rightc(_)).compose(I.inj)

      val prj = λ[FunctionK[EitherK[H, G, *], λ[α => Option[F[α]]]]](_.run.toOption.flatMap(I.prj(_)))
    }
}

object InjectK extends InjectKInstances {
  def apply[F[_], G[_]](implicit I: InjectK[F, G]): InjectK[F, G] = I
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy