What is the correct way to combine `Either.catch{....
# arrow
u
What is the correct way to combine
Either.catch{..}
and the
raise
DSL? I'm having the following problem:
either {
zipOrAccumulate(
{ ensureNotNull(<some function>) { MyErrorType1 },
{ ensureNotNull(<some other function>) { MyErrorType2 },
{ Either.catch { MyEnum.valueOf(someString) }.mapLeft { MyErrorType3 }
) { a, b, c -> MyType(a, b, c)
}
The
Either.catch
block does not type check, because the result is not compatible with the
raise
DSL. What is the idiomatic way to do it?
d
I think there's a catch function inside the dsl (w/o
Either.
)?
u
thanks!
👍🏼 1
So, for future reference, the solution is
either {
zipOrAccumulate(
{ ensureNotNull(<some function>) { MyErrorType1 },
{ ensureNotNull(<some other function>) { MyErrorType2 },
{ catch( { MyEnum.valueOf(someString) } ) { raise(MyErrorType3) } }
) { a, b, c -> MyType(a, b, c)
}
s
Uhm, not necessarily though! If you're in context of
Raise<E>
then you can call
Either.bind
on
Either<E, A>
. So I am assuming in this case that
MyErrorType1
,
MyErrorType2
and
MyErrorType3
have a common parent. I am going to define one
MyError
so:
Copy code
sealed interface MyError // (or sealed class)
object MyErrorType1 : MyError
object MyErrorType2 : MyError
object MyErrorType3 : MyError
And then we need to apply
bind
within your previous snippet so:
Copy code
either/*<NonEmptyList<MyError>, MyType>*/ { /* Raise<E>.() -> */
  zipOrAccumulate(
   { ensureNotNull(<some function>) { MyErrorType1 },
   { ensureNotNull(<some other function>) { MyErrorType2 },
   { Either.catch { MyEnum.valueOf(someString) }.mapLeft { MyErrorType3 }.bind() }
  ) { a, b, c -> MyType(a, b, c) }
}
Raise
, and
Either
are always interchangeable. To go from
Either<E, A>
to
A
in
Raise
you need to make sure that the generic parameter of
Raise
matches the error type of
Either
in this case
E
. (common parent). To go from
Raise<E>
to
A
you use the
either { }
builder, or DSL. Which you're also already using here. So if you work with
Either
using
either { }
, then you're in fact already using
Raise
all the time ☺️
I will also talk about this in my upcoming KotlinConf talk. The Arrow maintainers called this wrapped and unwrapped style. Where you can see
Either
as a "wrapper type", and
Raise<E>
relies on DSLs and never requires wrapping values. You can also see this all over the Kotlin ecosystem: •
Option
is a wrapper,
?
is unwrapped. •
Future
(wrapper), and as
suspend
(unwrapped) However, there are many people that prefer using
Either
over
Raise
(which kind-of implies context receivers to all benefits from it). At least, that is our prediction/expectation.
u
thanks for the explanation!
s
My pleasure ☺️