All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fj.data.Either3 Maven / Gradle / Ivy

Go to download

Functional Java is an open source library that supports closures for the Java programming language

The newest version!
package fj.data;

import fj.*;
import fj.function.Effect1;

import java.util.Collection;
import java.util.Iterator;

import static fj.Function.identity;
import static fj.P.p;
import static fj.Unit.unit;
import static fj.data.Array.mkArray;
import static fj.data.List.*;
import static fj.data.Option.none;
import static fj.data.Option.some;

public abstract class Either3 {

    private Either3() {}

    private static final class Left extends Either3 {
        private final A a;

        Left(A a) {
            this.a = a;
        }

        @Override
        public  D either(F fa, F fb, F fc) {
            return fa.f(a);
        }

    }

    private static final class Middle extends Either3 {
        private final B b;

        Middle(B b) {
            this.b = b;
        }

        @Override
        public  D either(F fa, F fb, F fc) {
            return fb.f(b);
        }
    }

    private static final class Right extends Either3 {
        private final C c;
        Right(C c) {
            this.c = c;
        }

        @Override
        public  D either(F fa, F fb, F fc) {
            return fc.f(c);
        }



    }

    public static final class LeftProjection {
        private final Either3 e;

        private LeftProjection(final Either3 e) {
            this.e = e;
        }

        public  Either3 apply(final Either3, B, C> e) {
            return e.left().bind(this::map);
        }

        public  Either3 bind(F> f) {
            return e.either(a -> f.f(a), b -> middle(b), c -> right(c));
        }

        public Either3 either() {
            return e;
        }

        public boolean exists(final F f) {
            return e.either(a -> f.f(a), b -> false, c -> false);
        }

        public  Option> filter(final F f) {
            return e.either(a -> f.f(a) ? some(left(a)) : none(), b -> none(), c -> none());
        }

        public boolean forall(final F f) {
            return e.either(a -> f.f(a), b -> true, c -> true);
        }

        public Unit foreach(final F f) {
            return e.either(a -> f.f(a), b -> unit(), c -> unit());
        }

        public void foreachDoEffect(final Effect1 f) {
            e.either(a -> f.toF().f(a), b -> unit(), c -> unit());
        }

        public Iterator iterator() {
            return toList().iterator();
        }

        public  Either3 map(final F f) {
            return e.either(a -> left(f.f(a)), b -> middle(b), c -> right(c));
        }

        public A orValue(final A value) {
            return orValue(() -> value);
        }

        public A orValue(final F0 f) {
            return e.either(a -> a, b -> f.f(), c -> f.f());
        }

        public  Either3 sequence(final Either3 e) {
            return bind(Function.constant(e));
        }

        public Array toArray() {
            return e.either(
                a -> Array.single(a),
                b -> Array.empty(),
                c -> Array.empty()
            );
        }

        public Collection toCollection() {
            return toList().toCollection();
        }

        public List toList() {
            return e.either(a -> single(a), b -> nil(), c -> nil());
        }

        public Option toOption() {
            return e.either(a -> some(a), b -> none(), c -> none());
        }

        public Stream toStream() {
            return e.either(a -> Stream.single(a), b -> Stream.nil(), c -> Stream.nil());
        }

        public  IO> traverseIO(final F> f) {
            return e.either(
                a -> f.f(a).map(Either3::left),
                b -> IOFunctions.unit(middle(b)),
                c -> IOFunctions.unit(right(c))
            );
        }

        public  List> traverseList1(final F> f) {
            return e.either(
                    a -> f.f(a).map(Either3::left),
                    b -> single(middle(b)),
                    c -> single(right(c))
            );
        }

        public  Option> traverseOption(final F> f) {
            return e.either(
                    a -> f.f(a).map(Either3::left),
                    b -> some(middle(b)),
                    c -> some(right(c))
            );

        }

        public  P1> traverseP1(final F> f) {
            return e.either(
                    a -> f.f(a).map(Either3::left),
                    b -> p(middle(b)),
                    c -> p(right(c))
            );

        }

        public  Stream> traverseStream(final F> f) {
            return e.either(
                    a -> f.f(a).map(Either3::left),
                    b -> Stream.single(middle(b)),
                    c -> Stream.single(right(c))
            );

        }

    }

    public static final class MiddleProjection {
        private final Either3 e;

        private MiddleProjection(final Either3 e) {
            this.e = e;
        }

        public  Either3 apply(final Either3, C> e) {
            return e.middle().bind(this::map);
        }

        public  Either3 bind(F> f) {
            return e.either(a -> left(a), b -> f.f(b), c -> right(c));
        }

        public Either3 either() {
            return e;
        }

        public boolean exists(final F f) {
            return e.either(a -> false, b -> f.f(b), c -> false);
        }

        public  Option> filter(final F f) {
            return e.either(a -> none(), b -> f.f(b) ? some(middle(b)) : none(), c -> none());
        }

        public boolean forall(final F f) {
            return e.either(a -> true, b -> f.f(b), c -> true);
        }

        public Unit foreach(final F f) {
            return e.either(a -> unit(), b -> f.f(b), c -> unit());
        }

        public void foreachDoEffect(final Effect1 f) {
            e.either(a -> unit(), b -> f.toF().f(b), c -> unit());
        }

        public Iterator iterator() {
            return toList().iterator();
        }

        public  Either3 map(final F f) {
            return e.either(a -> left(a), b -> middle(f.f(b)), c -> right(c));
        }

        public B orValue(final B value) {
            return orValue(() -> value);
        }

        public B orValue(final F0 f) {
            return e.either(a -> f.f(), b -> b, c -> f.f());
        }

        public  Either3 sequence(final Either3 e) {
            return bind(Function.constant(e));
        }

        public Array toArray() {
            return e.either(
                    a -> Array.empty(),
                    b -> Array.single(b),
                    c -> Array.empty()
            );
        }

        public Collection toCollection() {
            return toList().toCollection();
        }

        public List toList() {
            return e.either(a -> nil(), b -> single(b), c -> nil());
        }

        public Option toOption() {
            return e.either(a -> none(), b -> some(b), c -> none());
        }

        public Stream toStream() {
            return e.either(a -> Stream.nil(), b -> Stream.single(b), c -> Stream.nil());
        }

        public  IO> traverseIO(final F> f) {
            return e.either(
                    a -> IOFunctions.unit(left(a)),
                    b -> f.f(b).map(Either3::middle),
                    c -> IOFunctions.unit(right(c))
            );
        }

        public  List> traverseList1(final F> f) {
            return e.either(
                    a -> single(left(a)),
                    b -> f.f(b).map(Either3::middle),
                    c -> single(right(c))
            );
        }

        public  Option> traverseOption(final F> f) {
            return e.either(
                    a -> some(left(a)),
                    b -> f.f(b).map(Either3::middle),
                    c -> some(right(c))
            );

        }

        public  P1> traverseP1(final F> f) {
            return e.either(
                    a -> p(left(a)),
                    b -> f.f(b).map(Either3::middle),
                    c -> p(right(c))
            );

        }

        public  Stream> traverseStream(final F> f) {
            return e.either(
                    a -> Stream.single(left(a)),
                    b -> f.f(b).map(Either3::middle),
                    c -> Stream.single(right(c))
            );

        }


    }

    public final  Either3 leftMap(F f) {
        return left().map(f);
    }

    public final  F, Either3> leftMap_() {
        return this::leftMap;
    }

    public final  Either3 middleMap(F f) {
        return middle().map(f);
    }

    public final  F, Either3> middleMap_() {
        return this::middleMap;
    }

    public final  Either3 rightMap(F f) {
        return right().map(f);
    }

    public final  F, Either3> rightMap_() {
        return this::rightMap;
    }

    public static final class RightProjection {
        private final Either3 e;

        private RightProjection(final Either3 e) {
            this.e = e;
        }
        public  Either3 apply(final Either3> e) {
            return e.right().bind(this::map);
        }

        public  Either3 bind(F> f) {
            return e.either(a -> left(a), b -> middle(b), c -> f.f(c));
        }

        public Either3 either() {
            return e;
        }

        public boolean exists(final F f) {
            return e.either(a -> false, b -> false, c -> f.f(c));
        }

        public  Option> filter(final F f) {
            return e.either(a -> none(), b -> none(), c -> f.f(c) ? some(right(c)) : none());
        }

        public boolean forall(final F f) {
            return e.either(a -> true, b -> true, c -> f.f(c));
        }

        public Unit foreach(final F f) {
            return e.either(a -> unit(), b -> unit(), c -> f.f(c));
        }

        public void foreachDoEffect(final Effect1 f) {
            e.either(a -> unit(), b -> unit(), c -> f.toF().f(c));
        }

        public Iterator iterator() {
            return toList().iterator();
        }

        public  Either3 map(final F f) {
            return e.either(a -> left(a), b -> middle(b), c -> right(f.f(c)));
        }

        public C orValue(final C value) {
            return orValue(() -> value);
        }

        public C orValue(final F0 f) {
            return e.either(a -> f.f(), b -> f.f(), c -> c);
        }

        public  Either3 sequence(final Either3 e) {
            return bind(Function.constant(e));
        }

        public Array toArray() {
            return e.either(
                    a -> Array.empty(),
                    b -> Array.empty(),
                    c -> Array.single(c)
            );
        }

        public Collection toCollection() {
            return toList().toCollection();
        }

        public List toList() {
            return e.either(a -> nil(), b -> nil(), c -> single(c));
        }

        public Option toOption() {
            return e.either(a -> none(), b -> none(), c -> some(c));
        }

        public Stream toStream() {
            return e.either(a -> Stream.nil(), b -> Stream.nil(), c -> Stream.single(c));
        }

        public  IO> traverseIO(final F> f) {
            return e.either(
                    a -> IOFunctions.unit(left(a)),
                    b -> IOFunctions.unit(middle(b)),
                    c -> f.f(c).map(Either3::right)
            );
        }

        public  List> traverseList1(final F> f) {
            return e.either(
                    a -> single(left(a)),
                    b -> single(middle(b)),
                    c -> f.f(c).map(Either3::right)
            );
        }

        public  Option> traverseOption(final F> f) {
            return e.either(
                    a -> some(left(a)),
                    b -> some(middle(b)),
                    c -> f.f(c).map(Either3::right)
            );

        }

        public  P1> traverseP1(final F> f) {
            return e.either(
                    a -> p(left(a)),
                    b -> p(middle(b)),
                    c -> f.f(c).map(Either3::right)
            );

        }

        public  Stream> traverseStream(final F> f) {
            return e.either(
                    a -> Stream.single(left(a)),
                    b -> Stream.single(middle(b)),
                    c -> f.f(c).map(Either3::right)
            );

        }


    }

    public static  Either3 left(A a) {
        return new Left<>(a);
    }

    public static  F> left_() {
        return Either3::left;
    }

    public static  Either3 middle(B b) {
        return new Middle<>(b);
    }

    public static  Either3 right(C c) {
        return new Right<>(c);
    }

    public boolean isLeft() {
        return either(a -> true, b -> false, c -> false);
    }

    public boolean isMiddle() {
        return either(a -> false, b -> true, c -> false);
    }

    public boolean isRight() {
        return either(a -> false, b -> false, c -> true);
    }

    public  Either3 map3(F fl, F fm, F fr) {
        return either(
                a -> left(fl.f(a)),
                b -> middle(fm.f(b)),
                c -> right(fr.f(c))
        );
    }

    public abstract  D either(F fa, F fb, F fc);

    public static  F, D> either_(F fa, F fb, F fc) {
        return e -> e.either(fa, fb, fc);
    }

    public static  Either3 joinLeft(final Either3, B, C> e) {
        return e.left().bind(identity());
    }

    public static  Either3 joinMiddle(final Either3, C> e) {
        return e.middle().bind(identity());
    }

    public static  Either3 joinRight(final Either3> e) {
        return e.right().bind(identity());
    }

    public Either3 moveLeft() {
        return either(a -> right(a), b -> left(b), c -> middle(c));
    }

    public Either3 moveRight() {
        return either(a -> middle(a), b -> right(b), c -> left(c));
    }

    public Either3 swap() {
        return either(a -> right(a), b -> middle(b), c -> left(c));
    }

    public Either3 swapLefts() {
        return either(a -> middle(a), b -> left(b), c -> right(c));
    }

    public Either3 swapRights() {
        return either(a -> left(a), b -> right(b), c -> middle(c));
    }

    public Option leftOption() {
        return either(a -> some(a), b -> none(), c -> none());
    }

    public Option middleOption() {
        return either(a -> none(), b -> some(b), c -> none());
    }

    public Option rightOption() {
        return either(a -> none(), b -> none(), c -> some(c));
    }

    public final LeftProjection left() {
        return new LeftProjection<>(this);
    }

    public final MiddleProjection middle() {
        return new MiddleProjection<>(this);
    }

    public final RightProjection right() {
        return new RightProjection<>(this);
    }

    @Override
    public final boolean equals(Object other) {
        return Equal.equals0(Either3.class, this, other, () -> Equal.either3Equal(Equal.anyEqual(), Equal.anyEqual(), Equal.anyEqual()));
    }

    @Override
    public final int hashCode() {
        return Hash.either3Hash(Hash.anyHash(), Hash.anyHash(), Hash.anyHash()).hash(this);
    }

}