sean
07/17/2019, 9:04 PMfx
, Either
and coroutines
? I've been going over the documents and feel like I'm just missing something. I see effect but it looks like it's under the IO data type.Imran/Malic
07/17/2019, 9:17 PMImran/Malic
07/17/2019, 9:18 PMImran/Malic
07/17/2019, 9:21 PMsean
07/17/2019, 9:31 PMrestricted suspending function
. Which I saw referenced in a talk, and I believe was addressed using !effect { $item}
.
This is just a simple stub function to try and grok the fx
library with either. I was trying to clean up my code from Either.flatMap
or Either.fold
.pakoito
07/17/2019, 9:40 PMfx
. It only allows those defined for itself, which are all safe and nice.
You need a more powerful type to run all suspended functions, one that can wrap over them and handle errors, asynchrony and such. Those types we call effects
, and we have IO
as the main one built by us and wrappers for rx and project reactor.
So, starting in 0.10 you can do:
val result: IO<Either<String, Int>> = IO.fx {
...
val b = !effect { B() }
}
and somewhere in your code in another suspend function
suspend fun myLogic() {
val either = result.suspended()
}
In a future release this will become:
val result: IO<String, Int> = IO.fx {
...
}
where Either is implicit inside IO. We’re not there yet tho.sean
07/17/2019, 9:52 PMIO.fx
based on one of the linked talks. But was trying to figure out how to neatly operate on the right bias. But I guess that API is coming in the future. Changing that prior snippet
val result: IO<Either<String, Int>> = IO.fx {
val a = !effect { Right(5) }
val b = !effect { B() }
val c = !effect { Right(2) }
val d = a. + b + c
d
}
Where each item is a
val a : Either<String, Int>
...
So with that. Is there a doc or best practice for IO
and error handling? I had this snippet after reading the docs but it didn't feel idiomatic.
suspend fun sub(): Either<String, Int> = Right(2)
val result = IO.fx<Int> {
val a: Either<String, Int> = !effect { Right(5) }
val b: Either<String, Int> = !effect { sub() }
val c: Either<String, Int> = !effect { Right(2) }
val d = a.flatMap { A ->
b.flatMap { B ->
c.flatMap { C ->
Either.Right(A + B + C)
}
}
}
d.fold(
{ 0 },
{ it }
)
}
fun main() {
unsafe {
runBlocking {
IO.fx {
println(!effect { result })
}
}
}
}
pakoito
07/17/2019, 9:54 PMpakoito
07/17/2019, 10:00 PMsuspend fun sub(): Either<String, Int> = Right(2)
val result = IO.fx<Int> {
val a: Either<String, Int> = Right(5)
val b: Either<String, Int> = !effect { sub() } // effect only necessary for suspend functions
val c: Either<String, Int> = Right(2)
val exampleOne: IO<Int> = !pureRandomInt() // These three are the same
val exampleTwo: IO<Int> = pureRandomInt().bind() // Why do we have 3 versions?
val (exampleThree): IO<Int> = pureRandomInt() // We couldn't decide
val (one: Int, two: Int, three: Int) = !tupled(exampleOne, exampleTwo, exampleThree) // Combining destructuring and !
val d = Either.map(a, b, c) { (A, B, C) -> A + B + C }
d.getOrHandle { 0 }
}
fun main() {
unsafe {
runBlocking {
IO.fx {
println(!result)
}
}
}
}
sean
07/17/2019, 10:10 PMEither.map
method in my lib 0.9.1-SNAPSHOT
.
I also saw the following worked. After waiting for the coroutine side effects
suspend fun sub(): Either<String, Int> = Right(2)
val result = IO.fx {
val a: Either<String, Int> = !effect { Right(5) }
val b: Either<String, Int> = !effect { sub() }
val c: Either<String, Int> = !effect { Right(2) }
val d : Either<String,Int> = Either.fx<String,Int> {
!a + !b + !c
}
d.getOrHandle { 0 }
}
fun main() {
unsafe {
runBlocking {
IO.fx {
val (rsp) = !effect { result }
println(rsp)
}.unsafeRunSync()
}
}
}
Thanks again I had been banging my head against this for a day or twopakoito
07/17/2019, 10:11 PMpakoito
07/17/2019, 10:12 PMpakoito
07/17/2019, 10:12 PMval a: Either<String, Int> = !effect { Right(5) }
that extra effect is unnecessary, in case you’re not using it as an example for something elsepakoito
07/17/2019, 10:13 PMval (rsp) = !effect { result }
pakoito
07/17/2019, 10:13 PM!result
is enoughpakoito
07/17/2019, 10:14 PMeffect
only wraps suspend functions, otherwise it only returns the value inside, which you’re executing with (rsp)
destructuringsean
07/17/2019, 10:14 PM--refresh-dependencies
.
I'll be interested in seeing the new changes that are coming forwadpakoito
07/17/2019, 10:15 PMeffect { result }
is IO<IO<…>>, !effect { result }
is IO<…>, and that leads to val (rsp: ...) = !effect { result }
pakoito
07/17/2019, 10:16 PMval (rsp) = result
or val rsp = !result
is enoughsean
07/17/2019, 10:18 PM!
operator. It reminds me of F# and let!
syntaxpakoito
07/17/2019, 10:18 PM