Add Validation Applicative

Issue #35 new
Andrae Muys created an issue

I have sketched a possible approach to implementing a Validation Applicative for Fugue.

At the moment it is written using JDK8 lambdas; however, I don't believe this is required for correctness, just legibility.

I am interested in comments and critique.

https://bitbucket.org/snippets/atlassian/LAoK4

Comments (8)

  1. Anund McKague

    Base classes:

    class Validation<EE,A> {
        public abstract <B> B fold(Function<EE, B> onError, Function<A, B> onSuccess);
        public abstract <B> Validation<EE, B> map(Function<A, B> f);
        public abstract <B> Validation<EE, B> ap(SemiGroup<EE> s, Validation<EE, Function<A, B>> ff);
        protected abstract <B> B match(Function<Failure<EE,A>, B> onError, Function<Success<EE,A>, B> onSuccess);
    }
    
    // Builders
    static <EE, A> Validation<EE, A> succeed (A a){
       return new Success<>(a);
    }
    
    static <EE, A> Validation<EE, A> fail (EE e){
        return new Failure<>(e);
    }
    
    Class Success extends Validation<EE,A>
    Class Failure extends Validation<EE,A>
    
    SemiGroup<A> {
       A add(A a1, A a2);
    }
    
    SemiGroupApp<A,B> extends SemiGroup<A> {
       A point(B b); 
    }
    
  2. Anund McKague
    // lifts(?)
    public static <EE, A, R> Validation<EE, R> lift1(
           Validation<EE, A> fa,
           Function<A,R> f) {
        return fa.map(f);
    }
    public static <EE, A, B, R> Validation<EE, R> lift2(
            SemiGroup<EE> s,
            Validation<EE, A> fa,
            Validation<EE, B> fb,
            Function<A,Function<B,R>> f) {
        return fa.match(
                failure -> failure.accumulate(s, fb),
                success -> lift1(fb, f.apply(success.getValue())));
    }
    
    // accumulate
    protected <R> Validation<EE, R> accumulate(SemiGroup<EE> s, Validation<EE, ?> vb) {
        return accLoop(s, v -> v.failure(), vb);
    }
    
    protected <R> Validation<EE, R> accumulate(SemiGroup<EE> s, Validation<EE, ?> vb, Validation<EE, ?> vc, Validation<EE, ?> vd) {
        return accLoop(s, v -> v.accumulate(s, vc, vd), vb);
    }
    
    protected <R> Validation<EE, R> accLoop(SemiGroup<EE> s, Function<Failure<EE, ?>, Validation<EE, R>> acc, Validation<EE, ?> v) {
        return v.fold(ee -> acc.apply(failure(s.add(e, ee))), x -> acc.apply(this));
    }
    
  3. Anund McKague

    Possible additional behaviours:

    • leftmap(Function<A,B>)/bimap(Function<E,C>, Function<A,B)
    • extend maybe interface
    • success biased foreach
    • <* or *> chooseleft, chooseright given two validations ??
    • a swap Validation<A,B> to Validation<B,A>
  4. Jean-Baptiste Giraudeau

    Since Validation is isomorphic to Either, I think the approach of FJ - Validation just being a wrapper around Either with specialized/renamed methods - is good to maximize code reuse.

  5. Log in to comment