dave08
06/05/2025, 4:39 PMsimon.vergauwen
06/05/2025, 4:42 PMdave08
06/05/2025, 5:15 PMCLOVIS
06/06/2025, 8:04 AMleftFlatMap
but I don't know if Arrow has thatdave08
06/06/2025, 10:42 AMsimon.vergauwen
06/09/2025, 10:18 AMrecover
but recover
is actually more powerful. Normally this would be handleErrorWith
which is a more common name to flatMapLeft
, or handleError
for mapLeft
.
https://apidocs.arrow-kt.io/arrow-core/arrow.core/recover.html, recover
is the DSL version of both.simon.vergauwen
06/09/2025, 10:22 AMval original: Either<String, Int> = ...
val a: Either<Other, Int> =
original.handleErrorWith { msg -> Other(msg).left() }
// original.flatMapLeft { msg -> Other(msg).left() }
val b: Either<Other, Int> =
original.recover { msg -> raise(Other(msg)) }
val c: Either<Nothing, Int> =
original.recover { msg -> msg.length }
val d: Either<Nothing, Int> =
original.handleError { msg -> msg.length }
simon.vergauwen
06/09/2025, 10:23 AMgetOrElse
and withError
instead of recover
and flatMapLeft
though.simon.vergauwen
06/09/2025, 10:24 AMwithError({ msg -> msg.length }) { original.bind() }
msg.getOrElse { msg.length }
dave08
06/11/2025, 9:24 AMsimon.vergauwen
06/11/2025, 9:40 AMResult
is bound to Throwable
and recover
will allows raise
inside for the lambda.
You could only catch Throwable
if you're working with Either<Throwable, A>
, and in that case I guess we could project a recoverCatching
.
I assume you're looking for this because you want to avoid Result
due to it capturing CancellationException
?dave08
06/11/2025, 9:49 AMsimon.vergauwen
06/11/2025, 9:52 AMinline fun <E, A> Either<E, A>.recoverCatching(
onThrowable: Raise<E>.(Throwable) -> A,
block: Raise<E>.(E) -> A
): Either<E, A> = when(this) {
is Right -> this
is Left -> either {
catch({ block(value) }, onThrowable)
}
}
simon.vergauwen
06/11/2025, 9:56 AMEither<Throwable, A>
from all your (low-level?) operations, and use:
either<E, A> {
withError({ throwable -> throwable.toError() }) {
catch({
`bind` on `Either<E, A>` and `Either<Throwable, A>`
}) { throwable -> raise(throwable) }
}
}
With context parameters it can be a DSL.
inline fun <E, A> eitherCatching(
onThrowable: (Throwable) -> E,
block: context(Raise<E>, Raise<Throwable>) () -> A
): Either<E, A> = either<E, A> {
withError(onThrowable) {
catch({
block()
}) { throwable -> raise(throwable) }
}
}
dave08
06/11/2025, 11:48 AM