I have a couple of Vavr Either's and I want to invoke a function with the Right
value for each of these Either's. For example:
Either<MyError, String> either1 = ..
Either<MyError, String> either2 = ..
Either<MyError, String> either3 = ..
Either<MyError, String>> methodRequiringAllInputs(String, String, String) {
..
}
I could of course do something like this:
either1.flatMap { value1 ->
either2.flatMap { value2 ->
either3.flatMap { value3 ->
methodRequiringAllInputs(value1, value2, value3);
}
}
}
But this is very ugly. In other languages you could just use something like do-notation or for comprehensions to flatten out the structure. I know that Vavr has the concept of a Validation which is an applicative functor that allows you to do:
Validation<MyError, String> validation1 = ..
Validation<MyError, String> validation2 = ..
Validation<MyError, String> validation3 = ..
Validation.combine(validation1, validation2, validation3)
.ap((validationValue1,validationValue2,validationValue3) -> .. );
which is much nicer.
My question is if something similar exists in Vavr for Either's to avoid the nested flatMap
structure? Note that I don't want to convert the Either
's to Validation
's.
There's a for comprehension construct in vavr that you could use for your use case. It helps you transform multiple Iterable
, Option
, Try
, Future
or List
instances to another Iterator
, Option
, Try
, Future
or List
instance respectively, by combining them (as rows of their cartesian product) into result values.
In your case, Either
being an Iterable
on the right value, you can use the For
construct for Iterable
s to construct a Tuple3
of the String
right values, and iterate over the resulting Iterator
by invoking your side-effecting code, or mapping/transforming them in whatever way you want. You will have a rich vavr Iterator
, so that's a lot more flexible than a simple JDK Iterator
.
import static io.vavr.API.For;
For(either1, either2, either3)
.yield(Tuple::of)
.forEach(t -> methodRequiringAllInputs(t._1, t._2, t._3));
One small note though: in the above case, the result from the yield
is a lazily evaluated Iterator
. That means you'll need to iterate over it in the end in order to have the effects executed, so the forEach
part is essential. You cannot move the side-effecting code into the yield
part and skip the forEach
, as the yield
part will only be (lazily) executed when the resulting Iterator
is being iterated over.