Add a Task.tailRecM for stack safe loops (#846)

This commit is contained in:
P. Oscar Boykin 2018-04-28 00:00:09 -10:00 committed by Alexandre Archambault
parent c469899040
commit f003314317
2 changed files with 35 additions and 0 deletions

View File

@ -29,5 +29,18 @@ object Task extends PlatformTask {
def never[A]: Task[A] =
Task(_ => Promise[A].future)
def tailRecM[A, B](a: A)(fn: A => Task[Either[A, B]]): Task[B] =
Task[B] { implicit ec =>
def loop(a: A): Future[B] =
fn(a).future().flatMap {
case Right(b) =>
Future.successful(b)
case Left(a) =>
// this is safe because recursive
// flatMap is safe on Future
loop(a)
}
loop(a)
}
}

View File

@ -0,0 +1,22 @@
package coursier.util
import utest._
import scala.concurrent.{Await, ExecutionContext}
import scala.concurrent.duration.Duration
object TaskTests extends TestSuite {
val tests = Tests {
'tailRecM {
import ExecutionContext.Implicits.global
def countTo(i: Int): Task[Int] =
Task.tailRecM(0) {
case x if x >= i => Task.delay(Right(i))
case toosmall => Task.delay(Left(toosmall + 1))
}
countTo(500000).map(_ == 500000).future().map(assert(_))
}
}
}