Skip to content

Instantly share code, notes, and snippets.

@raulraja
Last active February 26, 2019 15:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raulraja/62de72039b11b05ed6d472cb8178da0c to your computer and use it in GitHub Desktop.
Save raulraja/62de72039b11b05ed6d472cb8178da0c to your computer and use it in GitHub Desktop.
Kotlin transformers encoding for `Death of Final Tagless` by John De Goes.
package arrow.effects.zio.example
/** Capabilities aggregation ala Kotlin **/
class Capabilities(
console: Console,
random: Random
) : Console by console, Random by random
package arrow.effects.zio.example
/** Console capability **/
interface Console {
fun <R> console(): Service<R>
companion object {
/** Algebra **/
interface Service<R> {
fun putStrLn(line: String): RIO<R, Unit>
fun getStrLn(): RIO<R, String>
}
interface Live : Console {
/** Interpreter **/
override fun <R> console(): Service<R> = object : Service<R> {
override fun putStrLn(line: String): RIO<R, Unit> =
rio { println(line) }
override fun getStrLn(): RIO<R, String> =
rio { readLine().orEmpty() }
}
companion object : Live
}
}
}
package arrow.effects.zio.example
/** Runtime implementation **/
object DefaultRuntime : Runtime<Capabilities> {
override val Environment: Capabilities
get() = Capabilities(
Console.Companion.Live,
Random.Companion.Live
)
}
package arrow.effects.zio.example
import arrow.core.Either
sealed class CustomError
object Stop : CustomError()
typealias Result<A> = Either<Throwable, Either<CustomError, A>>
package arrow.effects.zio.example
/** Concrete program **/
fun <R> program(): RIO<R, Unit> where R : Console, R : Random =
fx {
val mod: R = services()
val randomNumber = !mod.random<R>().randomInt()
!mod.console<R>().putStrLn("Found random int: $randomNumber")
!Stop.raiseError<R, Unit>()
}
/** Unsafe edge **/
fun main() {
val result: Result<Unit> = DefaultRuntime.unsafeRunBlocking(program())
println(result)
}
//Found random int: 1829110450
//Right(b=Left(a=arrow.effects.zio.Stop@726f3b58))
//Process finished with exit code 0
package arrow.effects.zio.example
import arrow.core.right
import arrow.data.*
import arrow.data.extensions.kleisli.monadError.monadError
import arrow.data.extensions.monadError
import arrow.effects.ForIO
import arrow.effects.IO
import arrow.effects.extensions.io.monad.monad
import arrow.typeclasses.Monad
import arrow.typeclasses.MonadContinuation
import arrow.typeclasses.MonadError
import kotlin.coroutines.startCoroutine
/** Arrow boilerplate since we don't have a ZIO<R, D, A> **/
typealias CustomErrors = EitherTPartialOf<ForIO, CustomError>
typealias RIO<R, A> = ReaderT<CustomErrors, R, A>
val ioMonad: Monad<ForIO> = IO.monad()
val errorMonad: MonadError<EitherTPartialOf<ForIO, CustomError>, CustomError> = EitherT.monadError(ioMonad)
fun <R> F(): MonadError<KleisliPartialOf<EitherTPartialOf<ForIO, CustomError>, R>, CustomError> = ReaderT.monadError(errorMonad)
typealias FxContinuation<R, A> = MonadContinuation<ReaderTPartialOf<EitherTPartialOf<ForIO, CustomError>, R>, A>
fun <R, A> fx(fa: suspend FxContinuation<R, *>.() -> A): RIO<R, A> {
val continuation: FxContinuation<R, A> = FxContinuation(F())
val wrapReturn: suspend FxContinuation<R, *>.() -> RIO<R, A> = { just(fa()).fix() }
wrapReturn.startCoroutine(continuation, continuation)
return continuation.returnedMonad().fix()
}
fun <R, A> CustomError.raiseError(): RIO<R, A> =
F<R>().run {
this@raiseError.raiseError<A>().fix()
}
suspend fun <R> FxContinuation<R, *>.services(): R =
!Kleisli.ask<EitherTPartialOf<ForIO, CustomError>, R>(errorMonad).fix()
fun <R, A> rio(fa: () -> A): RIO<R, A> =
ReaderT { EitherT(IO { fa().right() }) }
package arrow.effects.zio.example
/** Random Capability **/
interface Random {
fun <R> random(): Service<R>
companion object {
interface Service<R> {
fun randomInt(): RIO<R, Int>
}
interface Live : Random {
override fun <R> random(): Service<R> =
object : Service<R> {
override fun randomInt(): RIO<R, Int> =
rio { java.util.Random().nextInt() }
}
companion object : Live
}
}
}
package arrow.effects.zio.example
import arrow.data.fix
import arrow.effects.fix
/** Runtime module **/
interface Runtime<R> {
val Environment: R
fun <A> unsafeRunBlocking(rio: RIO<R, A>): Result<A> =
rio.run(Environment).fix().value().fix().attempt().unsafeRunSync()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment