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

libretto.lambda.MappedMorphism.scala Maven / Gradle / Ivy

The newest version!
package libretto.lambda

import libretto.lambda.util.{Functional, TypeEq}
import libretto.lambda.util.TypeEq.Refl

/** Image of some morphism `A -> B` in the target category `->>`.
 *
 * @tparam ->> target category
 * @tparam F   mapping of objects.
 *             `F[A, X]` is evidence that object `A` of the source category
 *             is mapped to object `X` of the target category.
 * @tparam A source of the original morphism in the source category
 * @tparam B target of the original morphism in the source category
 */
trait MappedMorphism[->>[_, _], F[_, _], A, B] {
  /** Source of the mapped morphism. Object of the target category. */
  type FA

  /** Target of the mapped morphism. Object of the target category. */
  type FB

  /** Evidence that the source `FA` of the mapped morphism is the image of the source `A` of the original morphism. */
  val srcMap: F[A, FA]

  /** Evidence that the target `FB` of the mapped morphism is the image of the target `B` of the original morphism. */
  val tgtMap: F[B, FB]

  /** The mapped morphism. */
  val ff: FA ->> FB

  def get[X, Y](fx: F[A, X], fy: F[B, Y])(using F: Functional[F]): X ->> Y =
    F.uniqueOutputType(srcMap, fx) match
      case TypeEq(Refl()) =>
        F.uniqueOutputType(tgtMap, fy) match
          case TypeEq(Refl()) =>
            ff

  def >[C](that: MappedMorphism[->>, F, B, C])(using
    F: Functional[F],
    cat: Semigroupoid[->>],
  ): MappedMorphism[->>,F, A, C] = {
    given (this.FB =:= that.FA) =
      F.uniqueOutputType(this.tgtMap, that.srcMap)

    MappedMorphism(
      this.srcMap,
      this.ff.to[that.FA] > that.ff,
      that.tgtMap,
    )
  }
}

object MappedMorphism {
  def apply[->>[_, _], F[_, _], X, Y, FX, FY](
    fx: F[X, FX],
    g: FX ->> FY,
    fy: F[Y, FY],
  ): MappedMorphism[->>, F, X, Y] =
    new MappedMorphism[->>, F, X, Y] {
      override type FA = FX
      override type FB = FY
      override val srcMap: F[X, FX] = fx
      override val tgtMap: F[Y, FY] = fy
      override val ff: FX ->> FY = g
    }

  def par[->>[_, _], F[_, _], <*>[_, _], |*|[_, _], A1, A2, B1, B2](
    f1: MappedMorphism[->>, F, A1, B1],
    f2: MappedMorphism[->>, F, A2, B2],
  )(using
    F: SemigroupalObjectMap[<*>, |*|, F],
    cat: SemigroupalCategory[->>, |*|],
  ): MappedMorphism[->>, F, A1 <*> A2, B1 <*> B2] =
    MappedMorphism(
      F.pair(f1.srcMap, f2.srcMap),
      cat.par(f1.ff, f2.ff),
      F.pair(f1.tgtMap, f2.tgtMap),
    )

  def composeFst[->>[_, _], F[_, _], <*>[_, _], |*|[_, _], A1, A2, B, Z1](
    h: MappedMorphism[->>, F, A1 <*> A2, B],
    g1: MappedMorphism[->>, F, Z1, A1],
  )(using
    F: SemigroupalObjectMap[<*>, |*|, F],
    cat: SemigroupalCategory[->>, |*|],
  ): MappedMorphism[->>, F, Z1 <*> A2, B] = {
    val f12 = F.unpair(h.srcMap)
    import f12.f2
    par(
      g1,
      MappedMorphism(f2, cat.id, f2),
    ) > h
  }

  def composeSnd[->>[_, _], F[_, _], <*>[_, _], |*|[_, _], A1, A2, B, Z2](
    h: MappedMorphism[->>, F, A1 <*> A2, B],
    g2: MappedMorphism[->>, F, Z2, A2],
  )(using
    F: SemigroupalObjectMap[<*>, |*|, F],
    cat: SemigroupalCategory[->>, |*|],
  ): MappedMorphism[->>, F, A1 <*> Z2, B] = {
    val f12 = F.unpair(h.srcMap)
    import f12.f1
    par(
      MappedMorphism(f1, cat.id, f1),
      g2,
    ) > h
  }

  def composeIntroFst[->>[_, _], F[_, _], <*>[_, _], |*|[_, _], One, Unit, A2, B](
    h: MappedMorphism[->>, F, One <*> A2, B],
  )(using
    F: MonoidalObjectMap[F, <*>, One, |*|, Unit],
    cat: MonoidalCategory[->>, |*|, Unit],
  ): MappedMorphism[->>, F, A2, B] = {
    val f12 = F.unpair(h.srcMap)
    import f12.{f1, f2}
    F.uniqueOutputType(f1, F.unit) match {
      case TypeEq(Refl()) =>
        MappedMorphism(f2, cat.introFst, F.pair(f1, f2)) > h
    }
  }

  def composeIntroSnd[->>[_, _], F[_, _], <*>[_, _], |*|[_, _], One, Unit, A1, B](
    h: MappedMorphism[->>, F, A1 <*> One, B],
  )(using
    F: MonoidalObjectMap[F, <*>, One, |*|, Unit],
    cat: MonoidalCategory[->>, |*|, Unit],
  ): MappedMorphism[->>, F, A1, B] = {
    val f12 = F.unpair(h.srcMap)
    import f12.{f1, f2}
    F.uniqueOutputType(f2, F.unit) match {
      case TypeEq(Refl()) =>
        MappedMorphism(f1, cat.introSnd, F.pair(f1, f2)) > h
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy