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

scalaz.BijectionT.scala Maven / Gradle / Ivy

The newest version!
package scalaz

import Id._

final class BijectionT[F[_], G[_], A, B] private[scalaz](_to: A => F[B], _from: B => G[A]) { self =>
  def to(a: A): F[B] = _to(a)
  def from(b: B): G[A] = _from(b)

  import BijectionT._
  import std.tuple._

  def flip: BijectionT[G, F, B, A] = new BijectionT[G, F, B, A](_from, _to)

  def toK: Kleisli[F, A, B] =
    Kleisli(_to)

  def fromK: Kleisli[G, B, A] =
    Kleisli(_from)

  def lens(implicit evF: F[B] === Id[B], evG: G[A] === Id[A]): Lens[A, B] =
    Lens(a => Store(b => evG(from(b)), evF(to(a))))

  def partial(implicit evF: F[B] === Id[B], evG: G[A] === Id[A]): PLens[A, B] =
    lens.partial

  /** alias for `partial` */
  def unary_~(implicit evF: F[B] === Id[B], evG: G[A] === Id[A]) : PLens[A, B] =
    partial

  def bimap[C, X[_, _], D](g: Bijection[C, D])(implicit F: Bifunctor[X], evF: F[B] === Id[B], evG: G[A] === Id[A]): Bijection[X[A, C], X[B, D]] =
    bijection(
      F.bimap(_)(_to andThen evF, g.to(_)): Id[X[B, D]]
    , F.bimap(_)(_from andThen evG, g.from(_)): Id[X[A, C]]
    )

  def ***[C, D](g: Bijection[C, D])(implicit evF: F[B] === Id[B], evG: G[A] === Id[A]): Bijection[(A, C), (B, D)] =
    bimap[C, Tuple2, D](g)

  def ^^^[C, D](g: Bijection[C, D])(implicit evF: F[B] === Id[B], evG: G[A] === Id[A]): Bijection[A \/ C, B \/ D] =
    bimap[C, \/, D](g)

  def compose[C](g: BijectionT[F, G, C, A])(implicit FM: Bind[F], GM: Bind[G]): BijectionT[F, G, C, B] =
    bijection(
      (toK <=< g.toK).run
    , (fromK >=> g.fromK).run
    )

  /** alias for `compose` */
  def <=<[C](that: BijectionT[F, G, C, A])(implicit FM: Bind[F], GM: Bind[G]): BijectionT[F, G, C, B] = compose(that)

  def andThen[C](that: BijectionT[F, G, B, C])(implicit M: Bind[F], GM: Bind[G]): BijectionT[F, G, A, C] =
    that compose this

  /** alias for `andThen` */
  def >=>[C](that: BijectionT[F, G, B, C])(implicit M: Bind[F], GM: Bind[G]): BijectionT[F, G, A, C] = andThen(that)

}
object BijectionT extends BijectionTInstances {
  def bijection[F[_], G[_], A, B](t: A => F[B], f: B => G[A]): BijectionT[F, G, A, B] =
    new BijectionT[F, G, A, B](t, f)

  import std.list._, std.function._

  type <@>[A, B] =
  Bijection[A, B]

  type Bijection[A, B] =
  BijectionT[Id, Id, A, B]

  def liftBijection[F[_], G[_], A, B](t: A => B, f: B => A)(implicit PF: Applicative[F], PG: Applicative[G]): BijectionT[F, G, A, B] =
    bijection(a => PF.point(t(a)), a => PG.point(f(a)))

  def bijectionId[F[_], G[_], A](implicit PF: Applicative[F], PG: Applicative[G]): BijectionT[F, G, A, A] =
    liftBijection(x => x, x => x)

  def curryB[A, B, C]: Bijection[(A, B) => C, A => B => C] =
    bijection[Id, Id, (A, B) => C, A => B => C](_.curried, Function.uncurried(_))

  // Left is true, Right is false
  def eitherB[A]: Bijection[A \/ A, (Boolean, A)] =
    bijection[Id, Id, A \/ A, (Boolean, A)]({
      case -\/(a) => (true, a)
      case \/-(a) => (false, a)
    }, {
      case (p, a) => if(p) -\/(a) else \/-(a)
    })

  def zipB[X[_], A, B](implicit Z: Zip[X], U: Unzip[X]): Bijection[(X[A], X[B]), X[(A, B)]] =
    bijection[Id, Id, (X[A], X[B]), X[(A, B)]](x => Z.zip(x._1, x._2), U.unzip(_))

  def zipListB[A, B]: Bijection[(List[A], List[B]), List[(A, B)]] =
    zipB[List, A, B]

  def zipIListB[A, B]: Bijection[(IList[A], IList[B]), IList[(A, B)]] =
    zipB[IList, A, B]

  def zipEndoB[A, B]: Bijection[(Endo[A], Endo[B]), Endo[(A, B)]] =
    zipB[Endo, A, B]

  def zipReaderB[T, A, B]: Bijection[(T => A, T => B), T => (A, B)] =
    zipB[T => *, A, B]

  def tuple3B[A, B, C]: Bijection[(A, B, C), (A, (B, C))] =
    bijection({ case (a, b, c) => (a, (b, c)) }, { case (a, (b, c)) => (a, b, c) })

  def tuple4B[ A, B, C, D]: Bijection[(A, B, C, D), (A, (B, (C, D)))] =
    bijection({ case (a, b, c, d) => (a, (b, (c, d))) }, { case (a, (b, (c, d))) => (a, b, c, d) })

  def tuple5B[ A, B, C, D, E]: Bijection[(A, B, C, D, E), (A, (B, (C, (D, E))))] =
    bijection({ case (a, b, c, d, e) => (a, (b, (c, (d, e)))) }, { case (a, (b, (c, (d, e)))) => (a, b, c, d, e) })

  def tuple6B[ A, B, C, D, E, H]: Bijection[(A, B, C, D, E, H), (A, (B, (C, (D, (E, H)))))] =
    bijection({ case (a, b, c, d, e, h) => (a, (b, (c, (d, (e, h))))) }, { case (a, (b, (c, (d, (e, h))))) => (a, b, c, d, e, h) })

  def tuple7B[ A, B, C, D, E, H, I]: Bijection[(A, B, C, D, E, H, I), (A, (B, (C, (D, (E, (H, I))))))] =
    bijection({ case (a, b, c, d, e, h, i) => (a, (b, (c, (d, (e, (h, i)))))) }, { case (a, (b, (c, (d, (e, (h, i)))))) => (a, b, c, d, e, h, i) })

}


sealed abstract class BijectionTInstances0 {
  implicit def bijectionTSplit[F[_], G[_]](implicit F0: Bind[F], G0: Bind[G]): Split[BijectionT[F, G, *, *]] =
    new BijectionTSplit[F, G] {
      override def F = F0
      override def G = G0
    }
}

sealed abstract class BijectionTInstances extends BijectionTInstances0 {
  implicit def bijectionTCategory[F[_], G[_]](implicit F0: Monad[F], G0: Monad[G]): Category[BijectionT[F, G, *, *]] =
    new BijectionTCategory[F, G] {
      override def F = F0
      override def G = G0
    }
}

private trait BijectionTSplit[F[_], G[_]] extends Split[BijectionT[F, G, *, *]] {
  implicit def F: Bind[F]
  implicit def G: Bind[G]

  def compose[A, B, C](bc: BijectionT[F, G, B, C], ab: BijectionT[F, G, A, B]): BijectionT[F, G, A, C] = ab >=> bc

  def split[A, B, C, D](ab: BijectionT[F, G, A, B], cd: BijectionT[F, G, C, D]): BijectionT[F, G, (A, C), (B, D)] =
    BijectionT.bijection(
      { case (a, c) => F.tuple2(ab.to(a), cd.to(c)) },
      { case (b, d) => G.tuple2(ab.from(b), cd.from(d)) }
    )
}

private trait BijectionTCategory[F[_], G[_]] extends Category[BijectionT[F, G, *, *]] with BijectionTSplit[F, G] {
  implicit def F: Monad[F]
  implicit def G: Monad[G]

  def id[A] = BijectionT.bijectionId
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy