dnowak
03/14/2023, 1:26 PMIO was in early versions of arrow?
2. Any advantage of using Effect compared to suspended function?
3. Where can I find some “reference” code showing how to use effects - combining small effects into larger ones, using effects in the application?simon.vergauwen
03/14/2023, 1:36 PMalpha to be released as 1.2.0-RC Effect is a typealias. typealias Effect<E, A> = suspend Raise<E>.() -> A. So you can say that suspend == IO and suspend Raise<E>.() -> A is EitherT<IO or a polymorphic version of suspend fun f(): Either<E, A> where Raise<E> can represent any data type (MonadError<F, E>).
2. They're equal. Effect is a suspend fun + the ability to work over typed errors of E.
3. We're working on some documentation/website still, but it's the same as working over suspend fun f(): Either<E, A>. If you were doing suspend fun f(): Either<E, A> = either { } today you can replace it with fun f(): Effect<E, A> = effect { }, suspend fun Raise<E>.f(): A or context(Raise<E>) suspend fun f(): A and all 3 works seamlessly together and are isomorphic with each-other. Note that val e: Either<E, A> is a value and val f: Effect<E, A> is a value of a computation.
For some examples, you can check:
• Ktor Example
• Ktor Example with Context Receivers
• Github Alerts Subscriptions
• Github Alerts Subscriptions with Context Receivers
If you were already familiar with EffectScope<E> and EagerEffectScope<E> then Raise<E> is simply the combination of the two. There is no more need to distinct between suspend and `non-suspend`(eager). We now leverage inline from the compiler to simplify this pattern and enable more powerful abstractions/patterns.dnowak
03/14/2023, 5:27 PMEffect<E, A> and suspended fun f(): Either<E, A> are equal why the effect was introduced?simon.vergauwen
03/14/2023, 5:42 PMEffect<E, A> (suspend Raise<E>.() -> A) is a DSL that enables syntax over Either<E, A> in a generic/polymorphic way.
Given context receivers lets consider the following:
context(arrow.core.raise.Raise<E>)
fun <E, A> io.vavr.control.Either<E, A>.bind(): A =
fold({ raise(it }, { it })
fun javaSdk(): io.vavr.control.Either<String, Int> =
io.vavr.control.Either.right(1)
fun otherCode(): arrow.core.Either<String, Int> =
arrow.core.Either.Right(1)
fun Raise<String>.one(): Int = 1
val x: arrow.core.Either<String, Int> = either {
javaSdk().bind() + otherCode().bind() + one()
}
fun Raise<String>.x2(): Int =
javaSdk().bind() + otherCode().bind() + one()
val f: Effect<String, Int> = ::x2simon.vergauwen
03/14/2023, 5:50 PMRaise<E> is the important piece, Effect<E, A> is just a typealias for suspend Raise<E>.() -> A. The either { } DSL is powered by Raise<E>, as well as many other types and offers the flexibility to bridge custom types into the DSL as well.
If you're familiar with Scala, or Haskell, you can consider Raise<E> final tagless to work over error types. It only defines E but not the container F.dnowak
03/15/2023, 2:06 PMsimon.vergauwen
03/15/2023, 2:06 PM