Hi <@U0RM4EPC7>. :wave: I get Either and Validated...
# arrow
o
Hi @simon.vergauwen. 👋 I get Either and Validated and I've learned, that Kotlin suspend is better than having IO wrappers. What's the benefit of
effect
? Please explain it to me like I'm five. 🙂
p
He wrote a blog post that covered it nicely (imo) https://nomisrev.github.io/continuation-monad-in-kotlin/
o
I've read it, but I still feel like I am missing something. Maybe I am just overthinking it. But how is that more useful than the core types? Could I traverse stuff with
effect
and chose if it's accumulating errors or short-circuit depending on the use-case?
b
Hi! Simon can answer better than me but with
Effect
type we introduce a new way to interrupt a continuation, we can interrupt it not only with throwables but also with custom error types, also we have in hands an effect system solution that we can encode our side-effects as pure values since the continuation is only created when you fold that effect, that means we can provide a pure environment to our impure functions just by calling it from an effect scope and we can assign it to whathever value that we want because we know we're not gonna break its purity. Also we have those benefits that you said, we can fold an effect into other types like Either, Validated, Ior or Option. With these benefits we can not only build computations and side effects in a "safer zone" but we have in hands literally an entire effect system to try new solutions and concepts like a different way to handle effect errors or other cool stuff.
👍 2
I'm current playing with that here, I'm focusing in find a good implementation to Algebraic Effects (it's just a new playground repo): https://github.com/bloderxd/kotlin-algebraic-effects/blob/main/src/main/kotlin/Example1.kt
p
What I still did not grok (from blog post and your description) is the passage:
Only when fold is called it will create a Continuation and run the computation, this means Effect can encode side-effects as pure values.
My understanding is that the
Effect
type represents a non-evaluated suspend function (i.e. something like a
Future
that is not started) and only when
fold
or
toEither
(
toIor
, …) is called on the
Effect
then the suspend function “underneath” it runs. But what
continuation
has to do with
fold
from the above citation is perplexing to me. EDIT: I looked at
Effect
and it overrides
fold
and does some black magic stuff with`continuation` inside it, maybe it would be good to elaborate how it works so ppl know what to expect from
Effect
API
r
A program on Effect is folded into a
successful
value
A
or a
shifted
value
E
. Internally it uses a try/catch and a controlled throwable.
Copy code
fun program(): Effect<E, A>
Since
Effect<E, A>
holds a suspend function it can model exit values for
A
,
E
and
Throwable
all potential valid results of folding
program
o
FP is cursed. 😞
p
no, FP is great, it just takes much longer to sink in, because all sophisticated concepts take long to sink in. Don't worry, I struggled for years, so it's normal 🙂
o
If it wasn't great, I wouldn't even bother. But it's definitely cursed. Ok...I don't want to waste your time venting my frustration, so have a nice Sunday and thanks Everyone! 👋
s
But it's definitely cursed.
😭 The goal of Arrow is to make FP simple, and idiomatic to Kotlin. So if we're doing something wrong, please help us improve it 🙏 TL;DR
effect
is useful for many things, but if you're current use-cases are fulfilled with
Either
and
Validated
then you can ignore it completely without missing out. Perhaps in the back of your head, it's interesting to know that
either { }
comes from
effect { }.toEither()
. Besides that, it can also be used to model lazy computations, as one might do with
IO
. Since passing around
Effect<E, A>
is likely nicer than passing around
suspend () -> Either<E, A>
.
Could I traverse stuff with
effect
and chose if it's accumulating errors or short-circuit depending on the use-case?
No, you cannot.
effect
models
short-circuit
behavior like
Either
such that the following results in the first
Error
encountered in
listOfValues
.
Copy code
effect<Error, Int> {
  listOfValues.map { it.bind() }
}
If you want
Validated
behavior then nothing changes with
Effect
.
👍 1
o
Hi Simon, thanks for answering. I'd like to help, but I don't see how atm. I could go on and ask "Why? / What kind of useful things?" multiple times, but that's a technique, that feels aggressive without seeing each other, so I'd rather not. Anyways, I think there's an opportunity to link https://arrow-kt.io/docs/effects/io/ ("Why
suspend () -> A
instead of *`IO<A>`*" ) and https://arrow-kt.io/docs/apidocs/arrow-core/arrow.core.continuations/-effect/. At least that was the gap I was trying to close by asking here... "Why
effect
instead of *`suspend () -> A`*" can't be answered by "If you find yourself passing around
suspend () -> Either<E, A>
a lot of times, you might want to use *`effect`*" because that sounds like
effect
was just a typealias and by the notion I got from all the answers here, there's a lot more to it than that. Maybe I'll be able to ask better questions re-reading @bloder’s answer a few more times. Need to let it sink in for now. 👋
👍 1
s
We have quite some work to do on the docs I would say, so any feedback is useful! So for us figuring out which parts of the documentation are lacking, or what kind of info is missing on what pages is extremely useful.
"If you find yourself passing around
suspend () -> Either<E, A>
a lot of times, you might want to use *`effect`*" because that sounds like
effect
was just a typealias and by the notion I got from all the answers here, there's a lot more to it than that.
100% valid. In reality that is already the short version since actually, it would be
suspend EffectScope<E>.() -> Either<E, A>
but that information seems useless to me if you're trying to understand
Effect
. So within Arrow, there are always 2 parts at play. The DSL
EffectScope<E>
which allows you to call
bind
,
ensure
,
ensureNotNull
etc inside
effect { }
,
either { }
, etc and the return type
Effect<E, A>
,
Either<E, A>
, etc. I think that is also never explained anywhere in Arrow but is not something that is explained in Kotlin in general I believe and this technique of building DSLs is super common in Kotlin Std, KotlinX Coroutines, KotlinX HTML, Gradle Kotlin Script, etc.
❤️ 1