Объединить Либо в Вавре?

У меня есть пара Vavr Either, и я хочу вызвать функцию со значением Right для каждого из этих Either. Например:

Either<MyError, String> either1 = ..
Either<MyError, String> either2 = ..
Either<MyError, String> either3 = ..

Either<MyError, String>> methodRequiringAllInputs(String, String, String) { 
..
}

Конечно, я мог бы сделать что-то вроде этого:

either1.flatMap { value1 ->
    either2.flatMap { value2 ->
        either3.flatMap { value3 ->
            methodRequiringAllInputs(value1, value2, value3);
        }
    }
}

Но это очень некрасиво. В других языках вы могли бы просто использовать что-то вроде do-notation или для понимания, чтобы сгладить структуру. Я знаю, что в Vavr есть концепция валидации, которая представляет собой аппликативный функтор, который позволяет вам сделать:

Validation<MyError, String> validation1 = ..
Validation<MyError, String> validation2 = ..
Validation<MyError, String> validation3 = ..

Validation.combine(validation1, validation2, validation3)
          .ap((validationValue1,validationValue2,validationValue3) -> .. );  

что намного приятнее.

Мой вопрос: существует ли что-то подобное в Vavr для Either's, чтобы избежать вложенной структуры flatMap? Обратите внимание, что я не хочу преобразовывать Either в Validation.


person Johan    schedule 09.01.2020    source источник


Ответы (1)


В vavr есть конструкция для понимания, которую вы можете использовать для своего варианта использования. Он помогает преобразовать несколько экземпляров Iterable, Option, Try, Future или List в другой экземпляр Iterator, Option, Try, Future или List соответственно, комбинируя их (как строки их декартовых произведений) в значения результатов.

В вашем случае, если Either является Iterable в правом значении, вы можете использовать конструкцию For для Iterables, чтобы построить Tuple3 из String правильных значений, и перебрать полученный Iterator, вызвав побочные эффекты код или отображение / преобразование их любым способом. У вас будет богатый vavr Iterator, так что он намного более гибкий, чем простой JDK Iterator.

import static io.vavr.API.For;

For(either1, either2, either3)
    .yield(Tuple::of)
    .forEach(t -> methodRequiringAllInputs(t._1, t._2, t._3));

Одно небольшое замечание: в приведенном выше случае результат yield - это ленивое вычисление Iterator. Это означает, что вам нужно будет перебрать его в конце, чтобы выполнить эффекты, поэтому часть forEach важна. Вы не можете переместить код с побочными эффектами в часть yield и пропустить forEach, поскольку часть yield будет выполняться (лениво) только при повторении результирующего Iterator.

person Nándor Előd Fekete    schedule 09.01.2020