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 eithersimon.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> = ::twodave08
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 availablesimon.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