```IO.parMapN(<http://Dispatchers.IO|Dispatchers.I...
# arrow
p
Copy code
IO.parMapN(<http://Dispatchers.IO|Dispatchers.IO>, ioS1, ioS2, ioS3) { a, b, c ->
  Either.map(a,b,c) { aa, bb, cc -> ... }
}
m
Thanks Paco. What is async about the unsafeRunAsync method then? I couldn't see any difference between it and unsafeRunSync
p
Sync blocks the thread, Async doesn’t. But if your code is run on the current thread anyway, they’ll work similarily
m
I couldn't find an Either.map method that worked like this, in the end, the following worked:
Copy code
@Test
    fun `io module test`() {
        val ioModule = Module(IO.async())
        ioModule.run {
            val ioS1 = repository.byId(u1).fix().attempt()
            val ioS2 = repository.byId(u2).fix().attempt()
            val ioS3 = repository.byId(u3).fix().attempt()

            val contextIO = IO.dispatchers().io()
            val contextS = <http://Schedulers.io|Schedulers.io>().asCoroutineContext()
            IO.parMapN(contextS, ioS1, ioS2, ioS3) { a, b, c ->
                ioInfo(a)
                ioInfo(b)
                ioInfo(c)
            }.unsafeRunSync()
        }
    }
Copy code
private val ioInfo: (Either<Throwable, Int>) -> Unit = { result ->
        when (result) {
            is Either.Right -> <http://logger.info|logger.info> { "got stock: ${result.b}" }
            is Either.Left -> logger.error { "error: ${result.a}" }
        }
    }
p
you’re side-effecting on the when, I would instead wrap it on an
IO
operation
like this
Copy code
fun IO<A>.logError(): IO<A> =
  attempt().flatMap { 
    it.fold(
      { IO { logger.error { "error: $it" } }.flatMap { raiseError(it) } }, 
      { IO.just(it).flatTap { IO { <http://logger.info|logger.info> { "got stock: $it" } } } }
    ) 
  }
and then
Copy code
val ioS1 = repository.byId(u1).fix().logError()
even better, make
<http://logger.info|logger.info>
a suspend function
to indicate it’s a side-effect
m
Very nice. In this case it's just a test class, so I just wanted to dump the results of the completed threads, so don't really mind it being side-effecty.
Coming back to your original code using
Either.map()
I found a map function on applicative(), so could do:
Copy code
Either.applicative<Throwable>().map(a, b) { (aa, bb) ->
    <http://logger.info|logger.info> { "T2 result: $aa, $bb"}
}
but I have to know that only 2 of the results were valid, one wasn't (it was an error). Using the triple version doesn't print anything (i.e.
map(a, b, c)
). Is there a way to map over all values without knowing how many were correct?
p
map
only works with 3 of them
sorry
I mean if all three of them are correct
if you want to side-effect on errors, or do something with them, you have to use
handleError
,
handleErrorWith
or even
mapLeft
m
Thanks. I'm learning lots. I found I can do
Either.applicative<Throwable>().tupled(a, b, c).fix()
which also combines into a left if there's an error too.
p
yep, it’s a specialized
Either.map
😄