-
-
Save raulraja/0088c4d41c3fdcf5aa77e73316f4af22 to your computer and use it in GitHub Desktop.
The following Gist demonstrates usage of `EnvFx`.
EnvFx is a data type that packs the Reader, Error and IO capabilities over the Kotlin suspended environment.
This models `Deps -> Either<Error, SuccessValue>` allowing to track algebras and effects as subtype contrains of a phantom type `R` that is carried around functions to provide syntactic ac…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The following Gist demonstrates usage of `EnvFx`. | |
* EnvFx is a data type that packs the Reader, Error and IO capabilities over the Kotlin suspended environment. | |
* This models `Deps -> Either<Error, SuccessValue>` allowing to track algebras and effects as subtype | |
* contrains of a phantom type `R` that is carried around programs to provide syntactic access to the service defined functions. | |
*/ | |
package arrow.effects | |
import arrow.core.Either | |
import arrow.effects.suspended.env.EnvFx | |
import arrow.effects.suspended.env.env | |
import arrow.effects.suspended.env.envfx.applicativeError.raiseError | |
import arrow.effects.suspended.env.envfx.fx.fx | |
import arrow.effects.suspended.env.toFx | |
import arrow.effects.suspended.fx.fx.unsafeRun.runBlocking | |
import arrow.unsafe | |
/** user algebra **/ | |
interface Service1 { | |
suspend fun foo(): Unit | |
} | |
/** user algebra **/ | |
interface Service2 { | |
suspend fun bar(): Unit | |
} | |
/** swapable interpreter **/ | |
object Service1Impl : Service1 { | |
override suspend fun foo(): Unit = | |
println("foo") | |
} | |
/** swapable interpreter **/ | |
object Service2Impl : Service2 { | |
override suspend fun bar(): Unit = | |
println("bar") | |
} | |
/** Module with services dependencies that fulfills the program constrains **/ | |
class Module( | |
service1: Service1 = Service1Impl, | |
service2: Service2Impl = Service2Impl | |
) : Service1 by service1, Service2 by service2 { | |
companion object { | |
fun impl(): Module = Module() | |
} | |
} | |
/** custom exceptionless error handling **/ | |
sealed class CustomError | |
object Stop : CustomError() | |
/** | |
* Programs declare the service they need by constraining the `R` type arg | |
* Each Service declaration over R needs to be fullfilled by an object that implements | |
* the service interfaces. | |
* | |
* `R` is exposed as this so the user has direct access to the syntax of the functions directly declared | |
* in the services without the need to prefix access with a service name. That is why you can invoke `foo` and `bar` direcly. | |
* `env` gives you this support placing `R` in the `this` scope | |
**/ | |
fun <R> program(): EnvFx<R, CustomError, Unit> | |
where R : Service1, R : Service2 = //R has Service1 and Service2 capabilities so we can invoke `foo` and `bar` polymorphically | |
env { | |
fx { | |
!effect { foo() } | |
!effect { bar() } | |
!Stop.raiseError<R, CustomError, Unit>() | |
} | |
} | |
/** | |
* You can go from `EnvFx` to `Fx` at the edge providing the dependency that fulfills your program | |
* constrains. | |
*/ | |
fun main() { | |
val result: Either<CustomError, Unit> = | |
unsafe { runBlocking { program<Module>().toFx(Module.impl()) } } | |
println(result) | |
//foo | |
//bar | |
//Left(a=arrow.effects.Stop@4c98385c) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment