package fj.data; import fj.Equal; import fj.F; import fj.F0; import fj.Function; import fj.Hash; import fj.P1; import fj.Show; import fj.Unit; import fj.function.Effect1; import java.util.Collection; import java.util.Iterator; import static fj.Bottom.error; import static fj.Function.compose; 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.cons_; import static fj.data.List.list; import static fj.data.List.single; import static fj.data.Option.some; /** * The <code>Either</code> type represents a value of one of two possible types (a disjoint union). * The data constructors; <code>Left</code> and <code>Right</code> represent the two possible * values. The <code>Either</code> type is often used as an alternative to * <code>scala.Option</code> where <code>Left</code> represents failure (by convention) and * <code>Right</code> is akin to <code>Some</code>. * * @version %build.number% */ public abstract class Either<A, B> { private Either() { } /** * Projects this either as a left. * * @return A left projection of this either. */ public final LeftProjection<A, B> left() { return new LeftProjection<>(this); } /** * Projects this either as a right. * * @return A right projection of this either. */ public final RightProjection<A, B> right() { return new RightProjection<>(this); } /** * Returns <code>true</code> if this either is a left, <code>false</code> otherwise. * * @return <code>true</code> if this either is a left, <code>false</code> otherwise. */ public abstract boolean isLeft(); /** * Returns <code>true</code> if this either is a right, <code>false</code> otherwise. * * @return <code>true</code> if this either is a right, <code>false</code> otherwise. */ public abstract boolean isRight(); /** * The catamorphism for either. Folds over this either breaking into left or right. * * @param left The function to call if this is left. * @param right The function to call if this is right. * @return The reduced value. */ public abstract <X> X either(final F<A, X> left, final F<B, X> right); /** * Map the given functions across the appropriate side. * * @param left The function to map if this is left. * @param right The function to map if this is right. * @return A new either value after mapping with the appropriate function applied. */ public final <X, Y> Either<X, Y> bimap(final F<A, X> left, final F<B, Y> right) { return either(compose(left_(), left), compose(right_(), right)); } @Override public final boolean equals(Object other) { return Equal.equals0(Either.class, this, other, () -> Equal.eitherEqual(Equal.anyEqual(), Equal.anyEqual())); } @Override public final int hashCode() { return Hash.eitherHash(Hash.<A>anyHash(), Hash.<B>anyHash()).hash(this); } /** * If this is a left, then return the left value in right, or vice versa. * * @return The value of this either swapped to the opposing side. */ public final Either<B, A> swap() { return either(right_(), left_()); } private static final class Left<A, B> extends Either<A, B> { private final A a; Left(final A a) { this.a = a; } public boolean isLeft() { return true; } public boolean isRight() { return false; } @Override public <X> X either(F<A, X> left, F<B, X> right) { return left.f(a); } } private static final class Right<A, B> extends Either<A, B> { private final B b; Right(final B b) { this.b = b; } public boolean isLeft() { return false; } public boolean isRight() { return true; } @Override public <X> X either(F<A, X> left, F<B, X> right) { return right.f(b); } } /** * A left projection of an either value. */ public static final class LeftProjection<A, B> implements Iterable<A> { private final Either<A, B> e; private LeftProjection(final Either<A, B> e) { this.e = e; } /** * Returns an iterator for this projection. This method exists to permit the use in a <code>for</code>-each loop. * * @return A iterator for this projection. */ public Iterator<A> iterator() { return toCollection().iterator(); } /** * The either value underlying this projection. * * @return The either value underlying this projection. */ public Either<A, B> either() { return e; } /** * Returns the value of this projection or fails with the given error message. * * @param err The error message to fail with. * @return The value of this projection */ public A valueE(final F0<String> err) { if (e.isLeft()) //noinspection CastToConcreteClass return ((Left<A, B>) e).a; else throw error(err.f()); } /** * Returns the value of this projection or fails with the given error message. * * @param err The error message to fail with. * @return The value of this projection */ public A valueE(final String err) { return valueE(p(err)); } /** * The value of this projection or fails with a specialised error message. * * @return The value of this projection. */ public A value() { return valueE(p("left.value on Right")); } /** * The value of this projection or the given argument. * * @param a The value to return if this projection has no value. * @return The value of this projection or the given argument. */ public A orValue(final F0<A> a) { return e.isLeft() ? value() : a.f(); } /** * The value of this projection or the given argument. * * @param a The value to return if this projection has no value. * @return The value of this projection or the given argument. */ public A orValue(final A a) { return e.isLeft() ? value() : a; } /** * The value of this projection or the result of the given function on the opposing projection's * value. * * @param f The function to execute if this projection has no value. * @return The value of this projection or the result of the given function on the opposing projection's * value. */ public A on(final F<B, A> f) { return e.isLeft() ? value() : f.f(e.right().value()); } /** * Execute a side-effect on this projection's value if it has one. * * @param f The side-effect to execute. * @return The unit value. */ public Unit foreach(final F<A, Unit> f) { if (e.isLeft()) f.f(value()); return unit(); } /** * Execute a side-effect on this projection's value if it has one. * * @param f The side-effect to execute. */ public void foreachDoEffect(final Effect1<A> f) { if (e.isLeft()) f.f(value()); } /** * Map the given function across this projection's value if it has one. * * @param f The function to map across this projection. * @return A new either value after mapping. */ public <X> Either<X, B> map(final F<A, X> f) { return e.isLeft() ? new Left<>(f.f(value())) : new Right<>(e.right().value()); } /** * Binds the given function across this projection's value if it has one. * * @param f The function to bind across this projection. * @return A new either value after binding. */ public <X> Either<X, B> bind(final F<A, Either<X, B>> f) { return e.isLeft() ? f.f(value()) : new Right<>(e.right().value()); } /** * Anonymous bind through this projection. * * @param e The value to bind with. * @return An either after binding through this projection. */ public <X> Either<X, B> sequence(final Either<X, B> e) { return bind(Function.constant(e)); } /** * Traverse with function that produces List (non-determinism). * * @param f the function to traverse with * @return An either after traversing through this projection. */ public <C> List<Either<C, B>> traverseList(final F<A, List<C>> f) { return e.isLeft() ? f.f(value()).map(Either::<C, B>left) : list(right(e.right().value())); } /** * Anonymous bind through this projection. * * @param f the function to traverse with * @return An either after traversing through this projection. */ public <C> IO<Either<C, B>> traverseIO(final F<A, IO<C>> f) { return e.isRight() ? IOFunctions.map(f.f(value()), Either::<C, B>left) : IOFunctions.unit(Either.right(e.right().value())); } /** * Returns <code>None</code> if this projection has no value or if the given predicate * <code>p</code> does not hold for the value, otherwise, returns a right in <code>Some</code>. * * @param f The predicate function to test on this projection's value. * @return <code>None</code> if this projection has no value or if the given predicate * <code>p</code> does not hold for the value, otherwise, returns a right in <code>Some</code>. */ public <X> Option<Either<A, X>> filter(final F<A, Boolean> f) { return e.isLeft() ? f.f(value()) ? some(new Left<>(value())) : Option.none() : Option.none(); } /** * Function application on this projection's value. * * @param e The either of the function to apply on this projection's value. * @return The result of function application within either. */ public <X> Either<X, B> apply(final Either<F<A, X>, B> e) { return e.left().bind(this::map); } /** * Returns <code>true</code> if no value or returns the result of the application of the given * function to the value. * * @param f The predicate function to test on this projection's value. * @return <code>true</code> if no value or returns the result of the application of the given * function to the value. */ public boolean forall(final F<A, Boolean> f) { return e.isRight() || f.f(value()); } /** * Returns <code>false</code> if no value or returns the result of the application of the given * function to the value. * * @param f The predicate function to test on this projection's value. * @return <code>false</code> if no value or returns the result of the application of the given * function to the value. */ public boolean exists(final F<A, Boolean> f) { return e.isLeft() && f.f(value()); } /** * Returns a single element list if this projection has a value, otherwise an empty list. * * @return A single element list if this projection has a value, otherwise an empty list. */ public List<A> toList() { return e.isLeft() ? single(value()) : List.nil(); } /** * Returns this projection's value in <code>Some</code> if it exists, otherwise * <code>None</code>. * * @return This projection's value in <code>Some</code> if it exists, otherwise * <code>None</code>. */ public Option<A> toOption() { return e.isLeft() ? some(value()) : Option.none(); } /** * Returns a single element array if this projection has a value, otherwise an empty array. * * @return A single element array if this projection has a value, otherwise an empty array. */ public Array<A> toArray() { if (e.isLeft()) { final Object[] a = new Object[1]; a[0] = value(); return mkArray(a); } else return mkArray(new Object[0]); } /** * Returns a single element stream if this projection has a value, otherwise an empty stream. * * @return A single element stream if this projection has a value, otherwise an empty stream. */ public Stream<A> toStream() { return e.isLeft() ? Stream.single(value()) : Stream.nil(); } /** * Projects an immutable collection of this projection. * * @return An immutable collection of this projection. */ public Collection<A> toCollection() { return toList().toCollection(); } public <C> Option<Either<C,B>> traverseOption(F<A, Option<C>> f) { return e.isLeft() ? f.f(value()).map(left_()) : some(right(e.right().value())); } public <C> Stream<Either<C, B>> traverseStream(F<A, Stream<C>> f) { return e.isLeft() ? f.f(value()).map(left_()) : Stream.single(right(e.right().value())); } } /** * A right projection of an either value. */ public static final class RightProjection<A, B> implements Iterable<B> { private final Either<A, B> e; private RightProjection(final Either<A, B> e) { this.e = e; } /** * Returns an iterator for this projection. This method exists to permit the use in a <code>for</code>-each loop. * * @return A iterator for this projection. */ public Iterator<B> iterator() { return toCollection().iterator(); } /** * The either value underlying this projection. * * @return The either value underlying this projection. */ public Either<A, B> either() { return e; } /** * Returns the value of this projection or fails with the given error message. * * @param err The error message to fail with. * @return The value of this projection */ public B valueE(final F0<String> err) { if (e.isRight()) //noinspection CastToConcreteClass return ((Right<A, B>) e).b; else throw error(err.f()); } /** * The value of this projection or fails with a specialised error message. * * @return The value of this projection. */ public B value() { return valueE(p("right.value on Left")); } /** * The value of this projection or the given argument. * * @param b The value to return if this projection has no value. * @return The value of this projection or the given argument. */ public B orValue(final F0<B> b) { return e.isRight() ? value() : b.f(); } /** * The value of this projection or the result of the given function on the opposing projection's * value. * * @param f The function to execute if this projection has no value. * @return The value of this projection or the result of the given function on the opposing projection's * value. */ public B on(final F<A, B> f) { return e.isRight() ? value() : f.f(e.left().value()); } /** * Execute a side-effect on this projection's value if it has one. * * @param f The side-effect to execute. * @return The unit value. */ public Unit foreach(final F<B, Unit> f) { if (e.isRight()) f.f(value()); return unit(); } /** * Execute a side-effect on this projection's value if it has one. * * @param f The side-effect to execute. */ public void foreachDoEffect(final Effect1<B> f) { if (e.isRight()) f.f(value()); } /** * Map the given function across this projection's value if it has one. * * @param f The function to map across this projection. * @return A new either value after mapping. */ public <X> Either<A, X> map(final F<B, X> f) { return e.isRight() ? new Right<>(f.f(value())) : new Left<>(e.left().value()); } /** * Binds the given function across this projection's value if it has one. * * @param f The function to bind across this projection. * @return A new either value after binding. */ public <X> Either<A, X> bind(final F<B, Either<A, X>> f) { return e.isRight() ? f.f(value()) : new Left<>(e.left().value()); } /** * Anonymous bind through this projection. * * @param e The value to bind with. * @return An either after binding through this projection. */ public <X> Either<A, X> sequence(final Either<A, X> e) { return bind(Function.constant(e)); } /** * Traverse with function that produces List (non-determinism). * * @param f the function to traverse with * @return An either after traversing through this projection. */ public <C> List<Either<A, C>> traverseList(final F<B, List<C>> f) { return e.isRight() ? f.f(value()).map(right_()) : list(left(e.left().value())); } /** * Traverse with a function that has IO effect * * @param f the function to traverse with * @return An either after traversing through this projection. */ public <C> IO<Either<A, C>> traverseIO(final F<B, IO<C>> f) { return e.isRight() ? IOFunctions.map(f.f(value()), right_()) : IOFunctions.lazy(() -> left(e.left().value())); } public <C> P1<Either<A, C>> traverseP1(final F<B, P1<C>> f) { return e.isRight() ? f.f(value()).map(right_()) : p(left(e.left().value())); } public <C> Option<Either<A, C>> traverseOption(final F<B, Option<C>> f) { return e.isRight() ? f.f(value()).map(right_()) : some(left(e.left().value())); } /** * Returns <code>None</code> if this projection has no value or if the given predicate * <code>p</code> does not hold for the value, otherwise, returns a left in <code>Some</code>. * * @param f The predicate function to test on this projection's value. * @return <code>None</code> if this projection has no value or if the given predicate * <code>p</code> does not hold for the value, otherwise, returns a left in <code>Some</code>. */ public <X> Option<Either<X, B>> filter(final F<B, Boolean> f) { return e.isRight() ? f.f(value()) ? some(new Right<X, B>(value())) : Option.none() : Option.none(); } /** * Function application on this projection's value. * * @param e The either of the function to apply on this projection's value. * @return The result of function application within either. */ public <X> Either<A, X> apply(final Either<A, F<B, X>> e) { return e.right().bind(this::map); } /** * Returns <code>true</code> if no value or returns the result of the application of the given * function to the value. * * @param f The predicate function to test on this projection's value. * @return <code>true</code> if no value or returns the result of the application of the given * function to the value. */ public boolean forall(final F<B, Boolean> f) { return e.isLeft() || f.f(value()); } /** * Returns <code>false</code> if no value or returns the result of the application of the given * function to the value. * * @param f The predicate function to test on this projection's value. * @return <code>false</code> if no value or returns the result of the application of the given * function to the value. */ public boolean exists(final F<B, Boolean> f) { return e.isRight() && f.f(value()); } /** * Returns a single element list if this projection has a value, otherwise an empty list. * * @return A single element list if this projection has a value, otherwise an empty list. */ public List<B> toList() { return e.isRight() ? single(value()) : List.nil(); } /** * Returns this projection's value in <code>Some</code> if it exists, otherwise * <code>None</code>. * * @return This projection's value in <code>Some</code> if it exists, otherwise * <code>None</code>. */ public Option<B> toOption() { return e.isRight() ? some(value()) : Option.none(); } /** * Returns a single element array if this projection has a value, otherwise an empty array. * * @return A single element array if this projection has a value, otherwise an empty array. */ public Array<B> toArray() { if (e.isRight()) { final Object[] a = new Object[1]; a[0] = value(); return mkArray(a); } else return Array.empty(); } /** * Returns a single element stream if this projection has a value, otherwise an empty stream. * * @return A single element stream if this projection has a value, otherwise an empty stream. */ public Stream<B> toStream() { return e.isRight() ? Stream.single(value()) : Stream.nil(); } /** * Projects an immutable collection of this projection. * * @return An immutable collection of this projection. */ public Collection<B> toCollection() { return toList().toCollection(); } public <C> Stream<Either<A, C>> traverseStream(F<B, Stream<C>> f) { return e.isRight() ? f.f(value()).map(Either::right) : Stream.single(left(e.left().value())); } } /** * Construct a left value of either. * * @param a The value underlying the either. * @return A left value of either. */ public static <A, B> Either<A, B> left(final A a) { return new Left<>(a); } /** * A function that constructs a left value of either. * * @return A function that constructs a left value of either. */ public static <A, B> F<A, Either<A, B>> left_() { return Either::left; } /** * A function that constructs a right value of either. * * @return A function that constructs a right value of either. */ public static <A, B> F<B, Either<A, B>> right_() { return Either::right; } /** * Construct a right value of either. * * @param b The value underlying the either. * @return A right value of either. */ public static <A, B> Either<A, B> right(final B b) { return new Right<>(b); } /** * First class catamorphism for either. Folds over this either breaking into left or right. * * @param left The function to call if this is left. * @param right The function to call if this is right. * @return The reducing function. */ public static <A, B, X> F<Either<A,B>, X> either_(final F<A, X> left, final F<B, X> right) { return e -> e.either(left, right); } /** * @return A function that maps another function across an either's left projection. */ public static <A, B, X> F<F<A, X>, F<Either<A, B>, Either<X, B>>> leftMap_() { return axf -> e -> e.left().map(axf); } /** * @return A function that maps another function across an either's right projection. */ public static <A, B, X> F<F<B, X>, F<Either<A, B>, Either<A, X>>> rightMap_() { return axf -> e -> e.right().map(axf); } /** * Joins an either through left. * * @param e The either of either to join. * @return An either after joining. */ public static <A, B> Either<A, B> joinLeft(final Either<Either<A, B>, B> e) { return e.left().bind(identity()); } /** * Joins an either through right. * * @param e The either of either to join. * @return An either after joining. */ public static <A, B> Either<A, B> joinRight(final Either<A, Either<A, B>> e) { return e.right().bind(identity()); } /** * Sequences through the left side of the either monad with a list of values. * * @param a The list of values to sequence with the either monad. * @return A sequenced value. */ public static <A, X> Either<List<A>, X> sequenceLeft(final List<Either<A, X>> a) { return a.isEmpty() ? left(List.nil()) : a.head().left().bind(aa -> sequenceLeft(a.tail()).left().map(cons_(aa))); } /** * Sequences through the right side of the either monad with a list of values. * * @param a The list of values to sequence with the either monad. * @return A sequenced value. */ public static <B, X> Either<X, List<B>> sequenceRight(final List<Either<X, B>> a) { return a.isEmpty() ? right(List.nil()) : a.head().right().bind(bb -> sequenceRight(a.tail()).right().map(cons_(bb))); } /** * Traversable instance of RightProjection of Either for List. * * @return traversed value */ public final <C> List<Either<A, C>> traverseListRight(final F<B, List<C>> f) { return right().traverseList(f); } /** * Traversable instance of LeftProjection of Either for List. * * @return traversed value */ public final <C> List<Either<C, B>> traverseListLeft(final F<A, List<C>> f) { return left().traverseList(f); } /** * Traversable instance of RightProjection of Either for IO. * * @return traversed value */ public final <C> IO<Either<A, C>> traverseIORight(final F<B, IO<C>> f) { return right().traverseIO(f); } /** * Traversable instance of LeftProjection of Either for IO. * * @return traversed value */ public final <C> IO<Either<C, B>> traverseIOLeft(final F<A, IO<C>> f) { return left().traverseIO(f); } /** * Traversable instance of RightProjection of Either for Option. * * @return traversed value */ public final <C> Option<Either<A, C>> traverseOptionRight(final F<B, Option<C>> f) { return right().traverseOption(f); } /** * Traversable instance of LeftProjection of Either for Option. * * @return traversed value */ public final <C> Option<Either<C, B>> traverseOptionLeft(final F<A, Option<C>> f) { return left().traverseOption(f); } /** * Traversable instance of RightProjection of Either for Stream. * * @return traversed value */ public final <C> Stream<Either<A, C>> traverseStreamRight(final F<B, Stream<C>> f) { return right().traverseStream(f); } /** * Traversable instance of LeftProjection of Either for Stream. * * @return traversed value */ public final <C> Stream<Either<C, B>> traverseStreamLeft(final F<A, Stream<C>> f) { return left().traverseStream(f); } /** * Takes an <code>Either</code> to its contained value within left or right. * * @param e The either to reduce. * @return An <code>Either</code> to its contained value within left or right. */ public static <A> A reduce(final Either<A, A> e) { return e.either(identity(), identity()); } /** * If the condition satisfies, return the given A in left, otherwise, return the given B in right. * * @param c The condition to test. * @param right The right value to use if the condition satisfies. * @param left The left value to use if the condition does not satisfy. * @return A constructed either based on the given condition. */ public static <A, B> Either<A, B> iif(final boolean c, final F0<B> right, final F0<A> left) { return c ? new Right<>(right.f()) : new Left<>(left.f()); } /** * Returns all the left values in the given list. * * @param es The list of possible left values. * @return All the left values in the given list. */ public static <A, B> List<A> lefts(final List<Either<A, B>> es) { return es.foldRight(e -> as -> e.isLeft() ? as.cons(e.left().value()) : as, List.nil()); } /** * Returns all the right values in the given list. * * @param es The list of possible right values. * @return All the right values in the given list. */ public static <A, B> List<B> rights(final List<Either<A, B>> es) { return es.foldRight(e -> bs -> e.isRight() ? bs.cons(e.right().value()) : bs, List.nil()); } public final String toString() { return Show.eitherShow(Show.<A>anyShow(), Show.<B>anyShow()).showS(this); } }