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