@@ -13,6 +13,8 @@ import arrow.effects.CancelToken
1313import arrow.effects.KindConnection
1414import arrow.effects.MVar
1515import arrow.effects.data.internal.BindingCancellationException
16+ import arrow.effects.internal.ConcurrentSleep
17+ import arrow.effects.internal.TimeoutException
1618import arrow.typeclasses.MonadContinuation
1719import java.util.concurrent.atomic.AtomicReference
1820import kotlin.coroutines.CoroutineContext
@@ -722,6 +724,90 @@ interface Concurrent<F> : Async<F> {
722724
723725 override fun <B > binding (c : suspend MonadContinuation <F , * >.() -> B ): Kind <F , B > =
724726 bindingCancellable { c() }.a
727+
728+ /* *
729+ * Sleeps for a given [duration] without blocking a thread.
730+ * Used to derive [waitFor] and can be used to created timed events like backing-off retries.
731+ *
732+ * ```kotlin:ank:playground
733+ * import arrow.*
734+ * import arrow.effects.*
735+ * import arrow.effects.typeclasses.*
736+ * import arrow.effects.extensions.io.concurrent.concurrent
737+ *
738+ * fun main(args: Array<String>) {
739+ * //sampleStart
740+ * fun <F> Concurrent<F>.delayHelloWorld(): Kind<F, Unit> =
741+ * sleep(3.seconds).flatMap {
742+ * delay { println("Hello World!") }
743+ * }
744+ * //sampleEnd
745+ * IO.concurrent().delayHelloWorld()
746+ * .fix().unsafeRunSync()
747+ * }
748+ * ```
749+ * @see waitFor
750+ **/
751+ fun sleep (duration : Duration ): Kind <F , Unit > = ConcurrentSleep (duration)
752+
753+ /* *
754+ * Returns the result of [this] within the specified [duration] or the [default] value.
755+ *
756+ * ```kotlin:ank:playground
757+ * import arrow.*
758+ * import arrow.effects.*
759+ * import arrow.effects.typeclasses.*
760+ * import arrow.effects.extensions.io.concurrent.concurrent
761+ *
762+ * fun main(args: Array<String>) {
763+ * //sampleStart
764+ * fun <F> Concurrent<F>.timedOutWorld(): Kind<F, Unit> {
765+ * val world = sleep(3.seconds).flatMap { delay { println("Hello World!") } }
766+ * val fallbackWorld = delay { println("Hello from the backup") }
767+ * return world.waitFor(1.seconds, fallbackWorld)
768+ * }
769+ * //sampleEnd
770+ * IO.concurrent().timedOutWorld()
771+ * .fix().unsafeRunSync()
772+ * }
773+ * ```
774+ **/
775+ fun <A > Kind <F , A >.waitFor (duration : Duration , default : Kind <F , A >): Kind <F , A > =
776+ dispatchers().default().raceN(this , sleep(duration)).flatMap {
777+ it.fold(
778+ { a -> just(a) },
779+ { default }
780+ )
781+ }
782+
783+ /* *
784+ * Returns the result of [this] within the specified [duration] or the raises a [TimeoutException] exception.
785+ *
786+ * ```kotlin:ank:playground
787+ * import arrow.*
788+ * import arrow.effects.*
789+ * import arrow.effects.typeclasses.*
790+ * import arrow.effects.extensions.io.concurrent.concurrent
791+ *
792+ * fun main(args: Array<String>) {
793+ * //sampleStart
794+ * fun <F> Concurrent<F>.timedOutWorld(): Kind<F, Unit> {
795+ * val world = sleep(1.seconds).flatMap { delay { println("Hello World!") } }
796+ * return world.waitFor(3.seconds)
797+ * }
798+ * //sampleEnd
799+ * IO.concurrent().timedOutWorld()
800+ * .fix().unsafeRunSync()
801+ * }
802+ * ```
803+ **/
804+ fun <A > Kind <F , A >.waitFor (duration : Duration ): Kind <F , A > =
805+ dispatchers().default().raceN(this , sleep(duration)).flatMap {
806+ it.fold(
807+ { a -> just(a) },
808+ { raiseError(TimeoutException (duration.toString())) }
809+ )
810+ }
725811}
726812
727813/* * Alias for `Either` structure to provide consistent signature for race methods. */
0 commit comments