PageRenderTime 40ms CodeModel.GetById 11ms app.highlight 22ms RepoModel.GetById 2ms app.codeStats 0ms

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