arrow-effects-reactor-extensions / arrow.effects.reactor.extensions.fluxk.monadThrow / bindingCatch

bindingCatch

@JvmName("bindingCatch") fun <B> bindingCatch(arg0: suspend MonadErrorContinuation<ForFluxK, *>.() -> B): FluxK<B>

Entry point for monad bindings which enables for comprehensions. The underlying implementation is based on coroutines. A coroutine is initiated and suspended inside MonadErrorContinuation yielding to Monad.flatMap. Once all the flatMap binds are completed, the underlying monad is returned from the act of executing the coroutine.

This one operates over MonadError instances that can support Throwable in their error type automatically lifting errors as failed computations in their monadic context and not letting exceptions thrown as the regular monad binding does.

Example

Oftentimes we find ourselves in situations where we need to sequence some computations that could potentially fail. bindingCatch allows us to safely compute those by automatically catching any exceptions thrown during the process.


import arrow.effects.reactor.*
import arrow.effects.reactor.extensions.fluxk.monadThrow.*
import arrow.core.*


import arrow.Kind
import arrow.typeclasses.MonadThrow

typealias Impacted = Boolean

object Nuke
object Target
class MissedByMeters(private val meters: Int) : Throwable("Missed by $meters meters")

fun <F> MonadThrow<F>.arm(): Kind<F, Nuke> = just(Nuke)
fun <F> MonadThrow<F>.aim(): Kind<F, Target> = just(Target)
fun <F> MonadThrow<F>.launchImpure(target: Target, nuke: Nuke): Impacted {
  throw MissedByMeters(5)
}

fun main(args: Array<String>) {
   //sampleStart
   fun <F> MonadThrow<F>.attack(): Kind<F, Impacted> =
     bindingCatch {
       val nuke = arm().bind()
       val target = aim().bind()
       val impact = launchImpure(target, nuke) // this throws!
       impact
     }

   val result = FluxK.monadThrow().attack()
   //sampleEnd
   println(result)
}