Reputation: 194
Is there a way to avoid the nesting in the code below when checking for errors without simply chaining functions?
val a: Either[Value, Exception]
val b: Either[Value, Exception]
val c: Either[Value, Exception]
def combine(a: Either[Value, Exception],
b: Either[Value, Exception],
c: Either[Value, Exception]) =
{
a match {
case Right(a) => Right(a)
case Left(a) => b match {
case Right(b) => Right(b)
case Left(b) => c match {
case Right(c) => Right(c)
case Left(c) => a + b + c
}
}
}
}
Upvotes: 0
Views: 119
Reputation: 48420
Since a
, b
, and c
are independent of each other Applicative
approach can also avoid "the pyramid of doom"
import cats.implicits._
(a, b, c).mapN(_ + _ + _)
of if you wish to keep the happy value on the left side, consider swapping the sides like so
import cats.implicits._
(a.swap, b.swap, c.swap).mapN(_ + _ + _).swap
Upvotes: 2
Reputation: 27535
First: by convention (imported from Haskell, where it made more sense) errors are Left
and correct values are Right
.
Once we establish that convention: .map
allows mapping Right value (it leaves Left
value intact) while .flatMap
allows you to turn Right
value into either Left
or Right
- on Right
it will continue composition, while Left
will break the circuit.
Having:
val a: Either[Exception, Value]
val b: Either[Exception, Value]
val c: Either[Exception, Value]
you could write:
val abc: Either[Exception, Value] =
a.flatMap { aValue =>
b.flatMap { bValue =>
c.map { cValue =>
(aValue, bValue, cValue)
}
}
}
which thanks to for comprehension can be written shorter as:
val abc = for {
aValue <- a
bValue <- b
cValue <- c
} yield (aValue, bValue, cValue)
However, if you use java.lang.Exception
as you error, then it would make more sense to use Try
because Try[A]
is very similar to Either[Throwable, A]
, except that it also can catch exceptions thrown inside of it (and is shorter to write).
Upvotes: 5