PageRenderTime 22ms CodeModel.GetById 11ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 1ms

/core/src/main/scala/scalaz/InvariantFunctor.scala

http://github.com/scalaz/scalaz
Scala | 75 lines | 33 code | 16 blank | 26 comment | 0 complexity | 0bc56ea07c21a45a603afd0c9c00861c MD5 | raw file
 1package scalaz
 2
 3////
 4/**
 5 * Unary type constructor that supports an `xmap` operation that converts an `F[A]` to an `F[B]` given
 6 * two functions, `A => B` and `B => A`.
 7 *
 8 * An invariant functor must satisfy two laws:
 9 *  - identity - xmap(ma)(identity, identity) == ma
10 *  - composite - xmap(xmap(ma, f1, g1), f2, g2) == xmap(ma, f2 compose f1, g1, compose g2)
11 *
12 * Also known as an exponential functor.
13 *
14 * @see [[https://hackage.haskell.org/packages/archive/invariant/latest/doc/html/Data-Functor-Invariant.html]]
15 * @see [[http://comonad.com/reader/2008/rotten-bananas/]]
16 *
17 * @see [[scalaz.InvariantFunctor.InvariantFunctorLaw]]
18 */
19////
20trait InvariantFunctor[F[_]]  { self =>
21  ////
22
23  import BijectionT.Bijection
24  import Isomorphism.<=>
25
26  /** Converts `ma` to a value of type `F[B]` using the provided functions `f` and `g`. */
27  def xmap[A, B](ma: F[A], f: A => B, g: B => A): F[B]
28
29  /** Converts `ma` to a value of type `F[B]` using the provided bijection. */
30  def xmapb[A, B](ma: F[A])(b: Bijection[A, B]): F[B] = xmap(ma, b.to, b.from)
31
32  /** Converts `ma` to a value of type `F[B]` using the provided isomorphism. */
33  def xmapi[A, B](ma: F[A])(iso: A <=> B): F[B] = xmap(ma, iso.to, iso.from)
34
35  trait InvariantFunctorLaw {
36
37    def invariantIdentity[A](fa: F[A])(implicit FA: Equal[F[A]]): Boolean =
38      FA.equal(xmap[A, A](fa, x => x, x => x), fa)
39
40    def invariantComposite[A, B, C](fa: F[A], f1: A => B, g1: B => A, f2: B => C, g2: C => B)(implicit FC: Equal[F[C]]): Boolean =
41      FC.equal(xmap(xmap(fa, f1, g1), f2, g2), xmap(fa, f2 compose f1, g1 compose g2))
42  }
43
44  def invariantFunctorLaw = new InvariantFunctorLaw {}
45  ////
46  val invariantFunctorSyntax: scalaz.syntax.InvariantFunctorSyntax[F] =
47    new scalaz.syntax.InvariantFunctorSyntax[F] { def F = InvariantFunctor.this }
48}
49
50object InvariantFunctor {
51  @inline def apply[F[_]](implicit F: InvariantFunctor[F]): InvariantFunctor[F] = F
52
53  import Isomorphism._
54
55  def fromIso[F[_], G[_]](D: F <~> G)(implicit E: InvariantFunctor[G]): InvariantFunctor[F] =
56    new IsomorphismInvariantFunctor[F, G] {
57      override def G: InvariantFunctor[G] = E
58      override def iso: F <~> G = D
59    }
60
61  ////
62  ////
63}
64
65trait IsomorphismInvariantFunctor[F[_], G[_]] extends InvariantFunctor[F] {
66  implicit def G: InvariantFunctor[G]
67  ////
68  import Isomorphism._
69
70  def iso: F <~> G
71
72  override def xmap[A, B](ma: F[A], f: A => B, g: B => A): F[B] =
73    iso.from(G.xmap(iso.to(ma), f, g))
74  ////
75}