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

scalaz.BindRec.scala Maven / Gradle / Ivy

package scalaz

////
/**
 * [[scalaz.Bind]] capable of using constant stack space when doing recursive
 * binds.
 *
 * Implementations of `tailrecM` should not make recursive calls without the
 * `@tailrec` annotation.
 *
  * Based on Phil Freeman's work on stack safety in PureScript, described in
  * [[http://functorial.com/stack-safety-for-free/index.pdf Stack Safety for
  * Free]].
 */
////
trait BindRec[F[_]] extends Bind[F] { self =>
  ////

  def tailrecM[A, B](f: A => F[A \/ B])(a: A): F[B]

  override def forever[A, B](fa: F[A]): F[B] =
    tailrecM[Unit, B](u => map(fa)(_ => -\/(u)))(())

  /**The product of BindRec `F` and `G`, `[x](F[x], G[x]])`, is a BindRec */
  def product[G[_]](implicit G0: BindRec[G]): BindRec[λ[α => (F[α], G[α])]] =
    new ProductBindRec[F, G] {
      def F = self
      def G = G0
    }

  trait BindRecLaw extends BindLaw {
    def tailrecBindConsistency[A](a: A, f: A => F[A])(implicit FA: Equal[F[A]]): Boolean = {
      val bounce = tailrecM[(Boolean, A), A] {
        case (bounced, a0) =>
          if (!bounced)
            map(f(a0))(a1 => -\/((true, a1)))
          else
            map(f(a0))(\/.right)
      }((false, a))

      FA.equal(bind(f(a))(f), bounce)
    }
  }
  def bindRecLaw = new BindRecLaw {}

  ////
  val bindRecSyntax = new scalaz.syntax.BindRecSyntax[F] { def F = BindRec.this }
}

object BindRec {
  @inline def apply[F[_]](implicit F: BindRec[F]): BindRec[F] = F

  ////

  ////
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy