/core/src/main/scala/scalaz/Bind.scala

http://github.com/scalaz/scalaz · Scala · 104 lines · 48 code · 18 blank · 38 comment · 1 complexity · e06b8bc8cf499a464c9f78474c398a02 MD5 · raw file

  1. package scalaz
  2. ////
  3. /**
  4. * An [[scalaz.Apply]] functor, where a lifted function can introduce
  5. * new values _and_ new functor context to be incorporated into the
  6. * lift context. The essential new operation of [[scalaz.Monad]]s.
  7. *
  8. * @see [[scalaz.Bind.BindLaw]]
  9. */
  10. ////
  11. trait Bind[F[_]] extends Apply[F] { self =>
  12. ////
  13. /** Equivalent to `join(map(fa)(f))`. */
  14. def bind[A, B](fa: F[A])(f: A => F[B]): F[B]
  15. // Derived combinators with big consequences:
  16. //
  17. // - ap must be sequential, f first then fa.
  18. // - apply2 must be sequential, fa first then fb.
  19. //
  20. // These are why IO is not parallel by default, by design.
  21. override def ap[A, B](fa: => F[A])(f: => F[A => B]): F[B] = {
  22. val fa0 = Need(fa)
  23. bind(f)(x => map(fa0.value)(x))
  24. }
  25. override def apply2[A, B, C](fa: => F[A], fb: => F[B])(f: (A, B) => C): F[C] = {
  26. val fb0 = Need(fb)
  27. bind(fa)(a => map(fb0.value)(b => f(a, b)))
  28. }
  29. /** Sequence the inner `F` of `FFA` after the outer `F`, forming a
  30. * single `F[A]`. */
  31. def join[A](ffa: F[F[A]]): F[A] = bind(ffa)(a => a)
  32. // derived functions
  33. /**
  34. * `if` lifted into a binding. Unlike `lift3((t,c,a)=>if(t)c else
  35. * a)`, this will only include context from the chosen of `ifTrue`
  36. * and `ifFalse`, not the other.
  37. */
  38. def ifM[B](value: F[Boolean], ifTrue: => F[B], ifFalse: => F[B]): F[B] = {
  39. val t = Need(ifTrue)
  40. val f = Need(ifFalse)
  41. bind(value)(if(_) t.value else f.value)
  42. }
  43. /** Pair `A` with the result of function application. */
  44. def mproduct[A, B](fa: F[A])(f: A => F[B]): F[(A, B)] =
  45. bind(fa)(a => map(f(a))((a, _)))
  46. /**The product of Bind `F` and `G`, `[x](F[x], G[x]])`, is a Bind */
  47. def product[G[_]](implicit G0: Bind[G]): Bind[λ[α => (F[α], G[α])]] =
  48. new ProductBind[F, G] {
  49. def F = self
  50. def G = G0
  51. }
  52. trait BindLaw extends ApplyLaw {
  53. /**
  54. * As with semigroups, monadic effects only change when their
  55. * order is changed, not when the order in which they're
  56. * combined changes.
  57. */
  58. def associativeBind[A, B, C](fa: F[A], f: A => F[B], g: B => F[C])(implicit FC: Equal[F[C]]): Boolean =
  59. FC.equal(bind(bind(fa)(f))(g), bind(fa)((a: A) => bind(f(a))(g)))
  60. /** `ap` is consistent with `bind`. */
  61. def apLikeDerived[A, B](fa: F[A], f: F[A => B])(implicit FB: Equal[F[B]]): Boolean =
  62. FB.equal(ap(fa)(f), bind(f)(f => map(fa)(f)))
  63. }
  64. def bindLaw = new BindLaw {}
  65. ////
  66. val bindSyntax: scalaz.syntax.BindSyntax[F] =
  67. new scalaz.syntax.BindSyntax[F] { def F = Bind.this }
  68. }
  69. object Bind {
  70. @inline def apply[F[_]](implicit F: Bind[F]): Bind[F] = F
  71. import Isomorphism._
  72. def fromIso[F[_], G[_]](D: F <~> G)(implicit E: Bind[G]): Bind[F] =
  73. new IsomorphismBind[F, G] {
  74. override def G: Bind[G] = E
  75. override def iso: F <~> G = D
  76. }
  77. ////
  78. ////
  79. }
  80. trait IsomorphismBind[F[_], G[_]] extends Bind[F] with IsomorphismApply[F, G]{
  81. implicit def G: Bind[G]
  82. ////
  83. override def bind[A, B](fa: F[A])(f: A => F[B]): F[B] =
  84. iso.from(G.bind(iso.to(fa))(f.andThen(iso.to.apply)))
  85. ////
  86. }