What is the idiomatic way of conditionally (i.e. o...
# arrow
l
What is the idiomatic way of conditionally (i.e. only for some specific cases) converting a
Left
to a
Right
? Like a
flatMapLeft()
.
Copy code
api.getUser().fold(
    ifLeft = { error ->
       if (error.code == 404) EmptyState.right() else ErrorState(error).left()
    },
    ifRight = { it.right() }
)
a
use
recover
thank you color 1
y
Copy code
api.getUser().recover { error ->
  if (error.code == 404) EmptyState else raise(ErrorState(error))
}
thank you color 1
arrow 1
l
Can I also do it inside an
either {}
builder?
a
yep, in that case you can make recover wrap around your code
Copy code
val x = recover({ api.getUser().bind() }) {
  when (it.code) {
    404 -> EmptyState
    else -> raise(EmptyState(error))
  }
}
l
Ah ok, that doesn't look that nice, but I suspect it doesn't fit in the
Raise
DSL otherwise?
a
yeah, giving two functional arguments to a function still looks kind of bad in Kotlin
y
You could do something like this, but idk if I'd recommend it:
Copy code
either {
  withError({ error: ErrorType -> if (error.code == 404) return@either EmptyState else ErrorState(error) }) {
    api.getUser().bind()
  }
}
This isn't in Arrow yet, but there's a PR that would allow something like:
Copy code
val x = either {
  val error = attempt { return@either api.getUsers.bind() }
  if (error.code == 404) EmptyState else raise(ErrorState(error))
}
It makes the code less nested, but it's quite imperative, especially with the early-return, and hence some people will dislike it. You can just replace
attempt
with
merge
if you want to try this today. There's a minor difference in type safety (attempt forces you to early-return, merge doesn't).
l
Yes, I was actually thinking of an early return. Especially with multiple subsequent calls inside an
either {}
block this could be actually a clearer syntax.
y
If you have more use cases for
attempt
, I'd love it if you replied with them here or on the PR!
👍 1
🙏 1