Search code examples
javafunctional-programmingmonadsvavr

Chaining functions that return Vavr Either


I have a series of functions that take in a Request object and return a Vavr Either.

The Either will contain a Result object if the task is complete or a modified Request object if the task needs to be completed by another function.

The thought was that I could chain them together by doing something like this:

// Note: The Request object parameter is modified by the function 
// before being returned in the Either.
Function<Request, Either<Request,Result>> function1;
Function<Request, Either<Request,Result>> function2;
Function<Request, Either<Request,Result>> function3;
Function<Request, Result> terminalFunction;

Result result = function1.apply(request)
            .flatMapLeft(function2)
            .flatMapLeft(function3)
            .fold(terminalFunction, r->r);

But apparently flatMapLeft is not a thing, so I just end up with a nested Eithers on the left side. Any ideas on how I can achieve this functionality? I'm open to alternative libraries.

Edit:

Result result = function1.apply(request)
            .fold(function2, Either::right)
            .fold(function3, Either::right)
            .fold(terminalFunction, r->r);

Seems like this should work instead, but Intellij is giving this error on the second fold line:

no instance(s) of type variable(s) exist so that capture of ? extends Object conforms to Request

Solution

  • You need monadic composition on your Request side, which is left side in your type signatures, but you have monadic composition for Either on the right side. So you need to swap your eithers in your function definitions or you have to pass them through Either.swap() with

    Function1.of(SomeType::function1).andThen(Either::swap)
    

    Essentially, each of your function[1-3] would then become of type:

    Function<Request, Either<Result, Request>>
    

    Then your call chain becomes:

    Result result = function1.apply(request)
            .flatMap(function2)
            .flatMap(function3)
            .swap()
            .getOrElseGet(terminalFunction);