Are there any documents for working with `fx`, `Ei...
# arrow
s
Are there any documents for working with
fx
,
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.
i
What exactly are you looking for?
If you struggle with finding something I always recommend arrow docset: https://github.com/i-walker/arrow-docset
It helps a lot if your new to where what is and gives you an offline search engine for the Arrow webpage. The last release is for 0.9.1 and 0.9.0, but it’s from April. Once we publish 0.10.0 in a few days I will update it, as we did a lot of changes
s
Thanks I'll take a look at the docs and see. What I'm running into is the
restricted 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
.
p
Right. So Either is an eager datatype that cannot allow running all suspended functions, even within
fx
. 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:
Copy code
val result: IO<Either<String, Int>> = IO.fx {
 ...
 val b = !effect { B() }
}
and somewhere in your code in another suspend function
Copy code
suspend fun myLogic() {
  val either = result.suspended()
}
In a future release this will become:
Copy code
val result: IO<String, Int> = IO.fx {
 ...
}
where Either is implicit inside IO. We’re not there yet tho.
s
Thanks for the detailed explinatioon I had looked at the
IO.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
Copy code
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
Copy code
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.
Copy code
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 })
            }
        }
    }
}
p
Right, gimme a couple of minutes to untangle 😄
Copy code
suspend 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)
            }
        }
    }
}
s
Thanks. this helps clear up a lot. I don't seem to have the
Either.map
method in my lib
0.9.1-SNAPSHOT
. I also saw the following worked. After waiting for the coroutine side effects
Copy code
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 two
p
Either.map is innnnn arrow-core in 0.9.1-SNAPSHOT, clear your cache and force to redownload depdendencies to get it
or go for 0.10.0-SNAPSHOT in a couple of days 😄
val a: Either<String, Int> = !effect { Right(5) }
that extra effect is unnecessary, in case you’re not using it as an example for something else
same for
val (rsp) = !effect { result }
!result
is enough
effect
only wraps suspend functions, otherwise it only returns the value inside, which you’re executing with
(rsp)
destructuring
s
I have an alias now for
--refresh-dependencies
. I'll be interested in seeing the new changes that are coming forwad
👍🏼 2
p
effect { result }
is IO<IO<…>>,
!effect { result }
is IO<…>, and that leads to
val (rsp: ...) = !effect { result }
you don’t need the extra step, so
val (rsp) = result
or
val rsp = !result
is enough
s
I'm really liking the
!
operator. It reminds me of F# and
let!
syntax
p
it’s literally the same, we lifted it from there 😄