/core/src/main/scala/scalaz/Bifunctor.scala

http://github.com/scalaz/scalaz · Scala · 100 lines · 56 code · 23 blank · 21 comment · 0 complexity · 933a3ab2c3e1badad494154189ecfc30 MD5 · raw file

  1. package scalaz
  2. ////
  3. /**
  4. * A type giving rise to two unrelated [[scalaz.Functor]]s.
  5. */
  6. ////
  7. trait Bifunctor[F[_, _]] { self =>
  8. ////
  9. /** `map` over both type parameters. */
  10. def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D]
  11. /**The composition of Bifunctors `F` and `G`, `[x,y]F[G[x,y],G[x,y]]`, is a Bifunctor */
  12. def compose[G[_, _]](implicit G0: Bifunctor[G]): Bifunctor[λ[(α, β) => F[G[α, β], G[α, β]]]] =
  13. new CompositionBifunctor[F, G] {
  14. implicit def F = self
  15. implicit def G = G0
  16. }
  17. /**The product of Bifunctors `F` and `G`, `[x,y](F[x,y], G[x,y])`, is a Bifunctor */
  18. def product[G[_, _]](implicit G0: Bifunctor[G]): Bifunctor[λ[(α, β) => (F[α, β], G[α, β])]] =
  19. new ProductBifunctor[F, G] {
  20. implicit def F = self
  21. implicit def G = G0
  22. }
  23. /** Extract the Functor on the first param. */
  24. def leftFunctor[X]: Functor[F[*, X]] =
  25. new LeftFunctor[F, X] {val F = self}
  26. def leftMap[A, B, C](fab: F[A, B])(f: A => C): F[C, B] =
  27. bimap(fab)(f, z => z)
  28. /** Extract the Functor on the second param. */
  29. def rightFunctor[X]: Functor[F[X, *]] =
  30. new RightFunctor[F, X] {val F = self}
  31. /** Unify the functor over both params. */
  32. def uFunctor: Functor[λ[α => F[α, α]]] =
  33. new UFunctor[F] {val F = self}
  34. def rightMap[A, B, D](fab: F[A, B])(g: B => D): F[A, D] =
  35. bimap(fab)(z => z, g)
  36. def umap[A, B](faa: F[A, A])(f: A => B): F[B, B] =
  37. bimap(faa)(f, f)
  38. /** Embed two Functors , one on each side */
  39. def embed[G[_],H[_]](implicit G0: Functor[G], H0: Functor[H]): Bifunctor[λ[(α, β) => F[G[α],H[β]]]] =
  40. new CompositionBifunctorFunctors[F,G,H] {
  41. def F = self
  42. def G = G0
  43. def H = H0
  44. }
  45. /** Embed one Functor to the left */
  46. def embedLeft[G[_]](implicit G0: Functor[G]): Bifunctor[λ[(α, β) => F[G[α],β]]] =
  47. embed[G,Id.Id]
  48. /** Embed one Functor to the right */
  49. def embedRight[H[_]](implicit H0: Functor[H]): Bifunctor[λ[(α, β) => F[α,H[β]]]] =
  50. embed[Id.Id,H]
  51. /** Bifunctors are covariant by nature */
  52. def widen[A, B, C >: A, D >: B](fab: F[A, B]): F[C, D] =
  53. bimap(fab)(identity[C], identity[D])
  54. ////
  55. val bifunctorSyntax: scalaz.syntax.BifunctorSyntax[F] =
  56. new scalaz.syntax.BifunctorSyntax[F] { def F = Bifunctor.this }
  57. }
  58. object Bifunctor {
  59. @inline def apply[F[_, _]](implicit F: Bifunctor[F]): Bifunctor[F] = F
  60. import Isomorphism._
  61. def fromIso[F[_, _], G[_, _]](D: F <~~> G)(implicit E: Bifunctor[G]): Bifunctor[F] =
  62. new IsomorphismBifunctor[F, G] {
  63. override def G: Bifunctor[G] = E
  64. override def iso: F <~~> G = D
  65. }
  66. ////
  67. ////
  68. }
  69. trait IsomorphismBifunctor[F[_, _], G[_, _]] extends Bifunctor[F] {
  70. implicit def G: Bifunctor[G]
  71. ////
  72. import Isomorphism._
  73. def iso: F <~~> G
  74. override def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D] =
  75. iso.from(G.bimap(iso.to(fab))(f, g))
  76. ////
  77. }