dave08
02/23/2023, 10:09 AMfun foo() = effect<Unit, Unit> { println("effect run") }
runBlocking {
either<Unit, Unit> {
foo().bind()
foo().bind()
}
}
And I get:
effect run
effect run
res4: arrow.core.Either<kotlin.Unit, kotlin.Unit> = Either.Right(kotlin.Unit)
That's a lazy computation only being done once? (I think I'm really NOT grasping this concept too much or not using it correctly... and to try digging into the source code isn't easy... and the kdocs are a mile long...)
My real question is: what are the PRACTICAL use cases for this structure...simon.vergauwen
02/23/2023, 10:22 AMval foo: Either<Unit, Unit> = either { println("either run") }
fun main() {
either {
foo.bind()
foo.bind()
}
}
either run
Either<Unit, Unit> = Either.Right(Unit)
vs
val foo: Effect<Unit, Unit> = effect { println("effect run") }
fun main() {
either {
foo.bind()
foo.bind()
}
}
effect run
effect run
Either<Unit, Unit> = Either.Right(Unit)
This is a proper example of non-lazy vs lazy.dave08
02/23/2023, 10:23 AMdave08
02/23/2023, 10:23 AMval foo by lazy {...}
simon.vergauwen
02/23/2023, 10:24 AMsimon.vergauwen
02/23/2023, 10:24 AMby lazy { }
, since by lazy
just makes the single computation lazy. You cannot invoke it many times.simon.vergauwen
02/23/2023, 10:25 AMby lazy
is a lazily computed value while Effect
is a lazy (function) value.dave08
02/23/2023, 10:26 AMval foo = foo.bind() // with effect
// then use
baz(foo)
// and not
baz(foo.bind())
// which is the same as using either
simon.vergauwen
02/23/2023, 10:26 AMEffect
is a simple typealias
so in reality you're writing val effect: suspend Raise<E>.() -> A
and calling bind
or invoke
on it.simon.vergauwen
02/23/2023, 10:26 AMEither
by itself.dave08
02/23/2023, 10:27 AMdave08
02/23/2023, 10:27 AMsimon.vergauwen
02/23/2023, 10:27 AMsuspend fun one(): Either<String, Int>
fun Raise<String>.two(): Int
val one: suspend () -> Either<String, Int> = ::one
val two: Effect<String, Int> = ::two
dave08
02/23/2023, 10:29 AMsimon.vergauwen
02/23/2023, 10:30 AMdave08
02/23/2023, 10:31 AMsimon.vergauwen
02/23/2023, 10:33 AMEither
value, rather than a function. I would say it's the same as passing around an Int
vs () -> Int
.
For example, I have written internally somewhere a library that uses Effect<E, A>
to model database queries that are lazily composable into transactions but once the transaction is made and ran I want to return a Either
value. Not a lazily computable transaction, that would be dangerous.simon.vergauwen
02/23/2023, 10:35 AMdave08
02/23/2023, 10:43 AMeither { }
when it doesn't matter that the computation is run on the spot, if one doesn't want to run it again, just save that result in a val
and re-use it. Only in specific cases one might use effect { }
to defer computation to a correct context, while defining it before use.dave08
02/23/2023, 10:43 AMdave08
02/23/2023, 10:45 AMeither { }
in a val
)dave08
02/23/2023, 10:55 AMJorge Bo
02/23/2023, 1:16 PMdave08
02/23/2023, 1:20 PMcatch({}, {})
(in the Raise DSL) for that?simon.vergauwen
02/23/2023, 1:36 PMEffect
encapsulates both Raise<E>
and suspend
. While Either
only captures E
into a value.
@dave08 catch({ }, { })
is Effect
since it only is available within either { }
and here { }
is `Raise<E>.() -> A`😅dave08
02/23/2023, 1:39 PMJorge Bo
02/23/2023, 1:43 PMJorge Bo
02/23/2023, 1:48 PMdave08
02/23/2023, 1:53 PMeffect { }
going to bubble up which isn't too FPish...? Shouldn't there just be a wrapper UnkownDomainError(val exception: Exception): DomainError
there?simon.vergauwen
02/23/2023, 1:57 PMUserNotFound
vs PSQLException(sqlState = Timeout)
. The first one should turn into a proper HttpStatusCode with a proper message, while the latter is just a 500
you cannot really do anything about. Except wrap some resilience safety around it.simon.vergauwen
02/23/2023, 1:58 PMUnkownDomainError
is better than this approach.simon.vergauwen
02/23/2023, 1:58 PMdave08
02/23/2023, 2:03 PMeither { }
so that really doesn't have to do with effect here, does it?simon.vergauwen
02/23/2023, 2:04 PMeffect
captures it in its signatures.dave08
02/23/2023, 2:05 PMdave08
02/23/2023, 2:05 PMeffect<Unit, Unit> { }
simon.vergauwen
02/23/2023, 2:06 PMeffect<String, Int> {
throw RuntimeException("Boom")
}.catch { e: RuntimeException -> 1 }
either<String, Int> {
throw RuntimeException("Boom")
} //.catch not available
simon.vergauwen
02/23/2023, 2:06 PMfold
, etc.Jorge Bo
02/23/2023, 2:07 PMdave08
02/23/2023, 2:10 PMdave08
02/23/2023, 2:18 PM