Skip to content
This repository has been archived by the owner on Feb 24, 2021. It is now read-only.

Re-encode bindings using arrow-continuations #252

Merged
merged 12 commits into from Oct 28, 2020
1 change: 1 addition & 0 deletions arrow-core-data/build.gradle
Expand Up @@ -11,6 +11,7 @@ apply from: "$DOC_CREATION"

dependencies {
api project(":arrow-annotations")
implementation project(":arrow-continuations")
kapt project(":arrow-meta")
kaptTest project(":arrow-meta")
compileOnly project(":arrow-meta")
Expand Down
Expand Up @@ -18,6 +18,7 @@ class ShortCircuit(val value: Any?) : RuntimeException(null, null) {
}

@Suppress("UNCHECKED_CAST")
@Deprecated("MonadContinuation is replaced by delimited continuations, please use DelimContScope instead")
internal abstract class MonadContinuation<F, A> : Continuation<Kind<F, A>>, EagerBind<F> {

abstract fun ShortCircuit.recover(): Kind<F, A>
Expand Down
Expand Up @@ -15,6 +15,7 @@ internal const val UNDECIDED = 0
internal const val SUSPENDED = 1

@Suppress("UNCHECKED_CAST")
@Deprecated("SuspendMonadContinuation is replaced by delimited continuations, please use DelimContScope instead")
internal abstract class SuspendMonadContinuation<F, A>(
private val parent: Continuation<Kind<F, A>>
) : Continuation<Kind<F, A>>, BindSyntax<F> {
Expand Down
16 changes: 8 additions & 8 deletions arrow-core-data/src/main/kotlin/arrow/core/Validated.kt
Expand Up @@ -148,10 +148,10 @@ typealias Invalid<E> = Validated.Invalid<E>
* suspend fun <A> parse(read: Read<A>, key: String) = validated<ConfigError, A> {
* val value = Validated.fromNullable(map[key]) {
* ConfigError.MissingConfig(key)
* }.bind()
* }()
* val readVal = Validated.fromOption(read.read(value)) {
* ConfigError.ParseConfig(key)
* }.bind()
* }()
* readVal
* }
* }
Expand Down Expand Up @@ -277,10 +277,10 @@ typealias Invalid<E> = Validated.Invalid<E>
* suspend fun <A> parse(read: Read<A>, key: String) = validated<ConfigError, A> {
* val value = Validated.fromNullable(map[key]) {
* ConfigError.MissingConfig(key)
* }.bind()
* }()
* val readVal = Validated.fromOption(read.read(value)) {
* ConfigError.ParseConfig(key)
* }.bind()
* }()
* readVal
* }.toValidatedNel()
* }
Expand Down Expand Up @@ -344,10 +344,10 @@ typealias Invalid<E> = Validated.Invalid<E>
* suspend fun <A> parse(read: Read<A>, key: String) = validated<ConfigError, A> {
* val value = Validated.fromNullable(map[key]) {
* ConfigError.MissingConfig(key)
* }.bind()
* }()
* val readVal = Validated.fromOption(read.read(value)) {
* ConfigError.ParseConfig(key)
* }.bind()
* }()
* readVal
* }.toValidatedNel()
* }
Expand Down Expand Up @@ -408,10 +408,10 @@ typealias Invalid<E> = Validated.Invalid<E>
* suspend fun <A> parse(read: Read<A>, key: String) = validated<ConfigError, A> {
* val value = Validated.fromNullable(map[key]) {
* ConfigError.MissingConfig(key)
* }.bind()
* }()
* val readVal = Validated.fromOption(read.read(value)) {
* ConfigError.ParseConfig(key)
* }.bind()
* }()
* readVal
* }
* }
Expand Down
52 changes: 16 additions & 36 deletions arrow-core-data/src/main/kotlin/arrow/core/computations/const.kt
@@ -1,49 +1,29 @@
package arrow.core.computations

import arrow.Kind
import arrow.continuations.generic.DelimContScope
import arrow.core.Const
import arrow.core.ConstOf
import arrow.core.ConstPartialOf
import arrow.core.EagerBind
import arrow.core.MonadContinuation
import arrow.core.ShortCircuit
import arrow.core.SuspendMonadContinuation
import arrow.core.value
import arrow.core.const
import arrow.core.fix
import arrow.typeclasses.suspended.BindSyntax
import kotlin.coroutines.Continuation
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn

object const {
fun <A, T> eager(c: suspend EagerBind<ConstPartialOf<A>>.() -> A): Const<A, T> {
val continuation: ConstContinuation<A, A> = ConstContinuation()
return continuation.startCoroutineUninterceptedAndReturn {
Const.just(c())
} as Const<A, T>
}

suspend operator fun <A, T> invoke(c: suspend BindSyntax<ConstPartialOf<A>>.() -> A): Const<A, T> =
suspendCoroutineUninterceptedOrReturn { cont ->
val continuation = ConstSContinuation(cont as Continuation<ConstOf<A, T>>)
continuation.startCoroutineUninterceptedOrReturn {
Const.just(c())
}
fun <A, T> eager(c: suspend EagerBind<ConstPartialOf<A>>.() -> A): Const<A, T> =
DelimContScope.reset {
c(object : EagerBind<ConstPartialOf<A>> {
override suspend fun <T> Kind<ConstPartialOf<A>, T>.invoke(): T =
fix().value() as T
}).const()
}

internal class ConstSContinuation<A, T>(
parent: Continuation<ConstOf<A, T>>
) : SuspendMonadContinuation<ConstPartialOf<A>, T>(parent) {
override fun ShortCircuit.recover(): Const<A, T> =
throw this

override suspend fun <B> Kind<ConstPartialOf<A>, B>.bind(): B =
value() as B
}

internal class ConstContinuation<A, T> : MonadContinuation<ConstPartialOf<A>, T>() {
override fun ShortCircuit.recover(): Const<A, T> =
throw this

override suspend fun <B> Kind<ConstPartialOf<A>, B>.bind(): B =
value() as B
}
suspend operator fun <A, T> invoke(c: suspend BindSyntax<ConstPartialOf<A>>.() -> A): Const<A, T> =
DelimContScope.reset {
c(object : BindSyntax<ConstPartialOf<A>> {
override suspend fun <T> Kind<ConstPartialOf<A>, T>.invoke(): T =
fix().value() as T
}).const()
}
}
60 changes: 24 additions & 36 deletions arrow-core-data/src/main/kotlin/arrow/core/computations/either.kt
@@ -1,50 +1,38 @@
package arrow.core.computations

import arrow.Kind
import arrow.continuations.generic.DelimContScope
import arrow.core.EagerBind
import arrow.core.Either
import arrow.core.EitherOf
import arrow.core.EitherPartialOf
import arrow.core.MonadContinuation
import arrow.core.ShortCircuit
import arrow.core.SuspendMonadContinuation
import arrow.core.fix
import arrow.core.identity
import arrow.typeclasses.suspended.BindSyntax
import kotlin.coroutines.Continuation
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn

object either {
fun <E, A> eager(c: suspend EagerBind<EitherPartialOf<E>>.() -> A): Either<E, A> {
val continuation: EitherContinuation<E, A> = EitherContinuation()
return continuation.startCoroutineUninterceptedAndReturn {
Either.Right(c())
} as Either<E, A>
}

suspend operator fun <E, A> invoke(c: suspend BindSyntax<EitherPartialOf<E>>.() -> A): Either<E, A> =
suspendCoroutineUninterceptedOrReturn { cont ->
val continuation = EitherSContinuation(cont as Continuation<EitherOf<E, A>>)
continuation.startCoroutineUninterceptedOrReturn {
Either.Right(c())
}
fun <E, A> eager(c: suspend EagerBind<EitherPartialOf<E>>.() -> A): Either<E, A> =
DelimContScope.reset {
Either.Right(
c(object : EagerBind<EitherPartialOf<E>> {
override suspend fun <A> Kind<EitherPartialOf<E>, A>.invoke(): A =
when (val v = fix()) {
is Either.Right -> v.b
is Either.Left -> shift { v }
}
})
)
}

internal class EitherSContinuation<E, A>(
parent: Continuation<EitherOf<E, A>>
) : SuspendMonadContinuation<EitherPartialOf<E>, A>(parent) {
override fun ShortCircuit.recover(): Kind<EitherPartialOf<E>, A> =
Either.Left(value as E)

override suspend fun <A> Kind<EitherPartialOf<E>, A>.bind(): A =
fix().fold({ e -> throw ShortCircuit(e) }, ::identity)
}

internal class EitherContinuation<E, A> : MonadContinuation<EitherPartialOf<E>, A>() {
override fun ShortCircuit.recover(): Kind<EitherPartialOf<E>, A> =
Either.Left(value as E)

override suspend fun <A> Kind<EitherPartialOf<E>, A>.bind(): A =
fix().fold({ e -> throw ShortCircuit(e) }, ::identity)
}
suspend operator fun <E, A> invoke(c: suspend BindSyntax<EitherPartialOf<E>>.() -> A): Either<E, A> =
DelimContScope.reset {
Either.Right(
c(object : BindSyntax<EitherPartialOf<E>> {
override suspend fun <A> Kind<EitherPartialOf<E>, A>.invoke(): A =
when (val v = fix()) {
is Either.Right -> v.b
is Either.Left -> shift { v }
}
})
)
}
}
53 changes: 18 additions & 35 deletions arrow-core-data/src/main/kotlin/arrow/core/computations/eval.kt
@@ -1,49 +1,32 @@
package arrow.core.computations

import arrow.Kind
import arrow.continuations.generic.DelimContScope
import arrow.core.EagerBind
import arrow.core.Eval
import arrow.core.EvalOf
import arrow.core.ForEval
import arrow.core.MonadContinuation
import arrow.core.ShortCircuit
import arrow.core.SuspendMonadContinuation
import arrow.core.fix
import arrow.typeclasses.suspended.BindSyntax
import kotlin.coroutines.Continuation
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn

object eval {
fun <A> eager(c: suspend EagerBind<ForEval>.() -> A): Eval<A> {
val continuation: EvalContinuation<A> = EvalContinuation()
return continuation.startCoroutineUninterceptedAndReturn {
Eval.just(c())
} as Eval<A>
}

suspend operator fun <A> invoke(c: suspend BindSyntax<ForEval>.() -> A): Eval<A> =
suspendCoroutineUninterceptedOrReturn { cont ->
val continuation = EvalSContinuation(cont as Continuation<EvalOf<A>>)
continuation.startCoroutineUninterceptedOrReturn {
Eval.just(c())
}
fun <A> eager(c: suspend EagerBind<ForEval>.() -> A): Eval<A> =
DelimContScope.reset {
Eval.just(
c(object : EagerBind<ForEval> {
override suspend fun <A> Kind<ForEval, A>.invoke(): A =
fix().value()
})
)
}

internal class EvalSContinuation<A>(
parent: Continuation<EvalOf<A>>
) : SuspendMonadContinuation<ForEval, A>(parent) {
override fun ShortCircuit.recover(): Kind<ForEval, A> =
throw this

override suspend fun <A> Kind<ForEval, A>.bind(): A =
fix().value()
}

internal class EvalContinuation<A> : MonadContinuation<ForEval, A>() {
override fun ShortCircuit.recover(): Kind<ForEval, A> =
throw this

override suspend fun <A> Kind<ForEval, A>.bind(): A =
fix().value()
}
suspend operator fun <A> invoke(c: suspend BindSyntax<ForEval>.() -> A): Eval<A> =
DelimContScope.reset {
Eval.just(
c(object : BindSyntax<ForEval> {
override suspend fun <A> Kind<ForEval, A>.invoke(): A =
fix().value()
})
)
}
}
@@ -1,52 +1,39 @@
package arrow.core.computations

import arrow.Kind
import arrow.continuations.generic.DelimContScope
import arrow.core.EagerBind
import arrow.core.Invalid
import arrow.core.MonadContinuation
import arrow.core.ShortCircuit
import arrow.core.SuspendMonadContinuation
import arrow.core.Valid
import arrow.core.Validated
import arrow.core.ValidatedOf
import arrow.core.ValidatedPartialOf
import arrow.core.fix
import arrow.core.identity
import arrow.typeclasses.suspended.BindSyntax
import kotlin.coroutines.Continuation
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn

object validated {
fun <E, A> eager(c: suspend EagerBind<ValidatedPartialOf<E>>.() -> A): Validated<E, A> {
val continuation: ValidatedContinuation<E, A> = ValidatedContinuation()
return continuation.startCoroutineUninterceptedAndReturn {
Valid(c())
} as Validated<E, A>
}

suspend operator fun <E, A> invoke(c: suspend BindSyntax<ValidatedPartialOf<E>>.() -> A): Validated<E, A> =
suspendCoroutineUninterceptedOrReturn { cont ->
val continuation = ValidatedSContinuation(cont as Continuation<ValidatedOf<E, A>>)
continuation.startCoroutineUninterceptedOrReturn {
Valid(c())
}
fun <E, A> eager(c: suspend EagerBind<ValidatedPartialOf<E>>.() -> A): Validated<E, A> =
DelimContScope.reset {
Valid(
c(object : EagerBind<ValidatedPartialOf<E>> {
override suspend fun <A> Kind<ValidatedPartialOf<E>, A>.invoke(): A =
when (val v = fix()) {
is Validated.Valid -> v.a
is Validated.Invalid -> shift { v }
}
})
)
}

internal class ValidatedSContinuation<E, A>(
parent: Continuation<ValidatedOf<E, A>>
) : SuspendMonadContinuation<ValidatedPartialOf<E>, A>(parent) {
override suspend fun <A> Kind<ValidatedPartialOf<E>, A>.bind(): A =
fix().fold({ e -> throw ShortCircuit(e) }, ::identity)

override fun ShortCircuit.recover(): Kind<ValidatedPartialOf<E>, A> =
Invalid(value as E)
}

internal class ValidatedContinuation<E, A> : MonadContinuation<ValidatedPartialOf<E>, A>() {
override suspend fun <A> Kind<ValidatedPartialOf<E>, A>.bind(): A =
fix().fold({ e -> throw ShortCircuit(e) }, ::identity)

override fun ShortCircuit.recover(): Kind<ValidatedPartialOf<E>, A> =
Invalid(value as E)
}
suspend operator fun <E, A> invoke(c: suspend BindSyntax<ValidatedPartialOf<E>>.() -> A): Validated<E, A> =
DelimContScope.reset {
Valid(
c(object : BindSyntax<ValidatedPartialOf<E>> {
override suspend fun <A> Kind<ValidatedPartialOf<E>, A>.invoke(): A =
when (val v = fix()) {
is Validated.Valid -> v.a
is Validated.Invalid -> shift { v }
}
})
)
}
}
Expand Up @@ -30,10 +30,10 @@ open class MonadContinuation<F, A>(

open fun returnedMonad(): Kind<F, A> = returnedMonad

override suspend fun <B> Kind<F, B>.bind(): B =
override suspend fun <A> Kind<F, A>.invoke(): A =
suspendCoroutineUninterceptedOrReturn { c ->
val labelHere = c.stateStack // save the whole coroutine stack labels
returnedMonad = this.flatMap { x: B ->
returnedMonad = this.flatMap { x: A ->
c.stateStack = labelHere
c.resume(x)
returnedMonad
Expand Down
Expand Up @@ -70,8 +70,8 @@ interface MonadError<F, E> : ApplicativeError<F, E>, Monad<F> {
* //sampleStart
* fun <F> MonadThrow<F>.prepareLunch(): Kind<F, Salad> =
* fx.monadThrow {
* val lettuce = takeFoodFromRefrigerator().bind()
* val knife = getKnife().bind()
* val lettuce = takeFoodFromRefrigerator()()
* val knife = getKnife()()
* val salad = launchImpure(knife, lettuce) // this throws!
* salad
* }
Expand Down Expand Up @@ -120,8 +120,8 @@ interface MonadThrow<F> : MonadError<F, Throwable> {
* //sampleStart
* fun <F> MonadThrow<F>.prepareLunch(): Kind<F, SaladPrepared> =
* fx.monadThrow {
* val lettuce = takeFoodFromRefrigerator().bind()
* val knife = getKnife().bind()
* val lettuce = takeFoodFromRefrigerator()()
* val knife = getKnife()()
* val salad = launchImpure(knife, lettuce) // this throws!
* salad
* }
Expand Down