I was kind of surprised that the `map { }` and `fl...
# arrow
d
I was kind of surprised that the
map { }
and
flatMap { }
on Either don't have a
Raise<...>
as the receiver for their lambdas... wouldn't it be great to be able to raise inside
map { }
if something didn't work out with the mapping?
y
For
map
it doesn't make much sense since map is meant to always succeed. For
flatMap
, you can do
flatMap { either { } }
s
There is some best practices in API design that dictate agains this.
flatMap
is pretty much there because it's well known, and so compose method references.
Copy code
either {
  f(fa.bind())
}
vs
Copy code
fa.flatMap { a ->
  f(a)
}
The difference is extremely minimal, the benefit of the former is that it scales. As in you can add chain more code without needing more operators (or wrapping) In addition to it being uniform with all other code, "single API to rule them all". Anyhow, it's perfectly possible to add
Raise<E>
to
flatMap
, I think it doesn't make sense in
map
though 🤔 It would change the meaning of
map
, giving it the same powers as
flatMap
.
c
Thinking about it this way,
recover
is essentially “`flatMapLeft` with `Raise`”, no?
s
Yes, exactly.
flatMapLeft
was named
handleErrorWith
before
c
If
flatMap
with
Raise
gets added, I vote for it to be called
then
; but I'm not sure it's necessary. AFAIK it's the same functionality as
bind
, but with added indentation. I much prefer:
Copy code
fun a(): Either<E, A>
fun b(b: A): Either<E, B>
fun foo() = either {
    b(a().bind()).bind()
}
or even better:
Copy code
context(Raise<E>) fun a(): A
context(Raise<E>) fun b(b: A): B
context(Raise<E>) fun foo(): B {
    b(a())
}
than
Copy code
fun a(): Either<E, A>
fun b(b: A): Either<E, B>
fun foo() = a.flatMap { b(it) }
Although, in this specific example, the
flatMap
example is quite readable, but that's mainly because it's such a simple case. In the real world, I find
flatMap
to often make code harder to read
1
d
My original understanding was due to Kotlin.Result having
mapCatching { }
... and my use-case is in a function that I receive an Either as a parameter, and just want to transform the Right or handle errors in the transformation... so I don't have an either { } block around it. I was kind of expecting some function to allow me to do using Raise<...> api instead of the verbosity of flatmap and tagging .right() and .left() and leaving the happy path processing to having to handle both happy/unhappy paths...
Raise<> is also unhappy path handling, but can be easily encapsulated in another function...