mirror of https://github.com/sbt/sbt.git
Add a Task.tailRecM for stack safe loops (#846)
This commit is contained in:
parent
c469899040
commit
f003314317
|
|
@ -29,5 +29,18 @@ object Task extends PlatformTask {
|
||||||
def never[A]: Task[A] =
|
def never[A]: Task[A] =
|
||||||
Task(_ => Promise[A].future)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(_))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue