Mercurial > hg > Members > tatsuki > functionaljava-master > core
view src/main/java/fj/data/Either.java @ 0:fe80c1edf1be
add getLoop
author | tatsuki |
---|---|
date | Fri, 20 Mar 2015 21:04:03 +0900 |
parents | |
children |
line wrap: on
line source
package fj.data; import static fj.Bottom.error; import fj.Effect; import fj.F; import static fj.Function.identity; import static fj.P.p; import fj.Show; import fj.Function; import fj.P1; import fj.Unit; import fj.function.Effect1; import static fj.Unit.unit; import static fj.data.Array.mkArray; import static fj.data.List.single; import static fj.data.List.cons_; import static fj.data.Option.some; import java.util.Collection; import java.util.Iterator; /** * 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<A, B>(this); } /** * Projects this either as a right. * * @return A right projection of this either. */ public final RightProjection<A, B> right() { return new RightProjection<A, B>(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 final <X> X either(final F<A, X> left, final F<B, X> right) { return isLeft() ? left.f(left().value()) : right.f(right().value()); } /** * 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 isLeft() ? new Right<B, A>(((Left<A, B>) this).a) : new Left<B, A>(((Right<A, B>) this).b); } 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; } } 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; } } /** * A left projection of an either value. */ public 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 P1<String> err) { if (e.isLeft()) //noinspection CastToConcreteClass return ((Left<A, B>) e).a; else throw error(err._1()); } /** * 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 P1<A> a) { return isLeft() ? value() : a._1(); } /** * 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 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 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 (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 (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 isLeft() ? new Left<X, B>(f.f(value())) : new Right<X, B>(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 isLeft() ? f.f(value()) : new Right<X, B>(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.<A, Either<X, B>>constant(e)); } /** * 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 isLeft() ? f.f(value()) ? Option.<Either<A, X>>some(new Left<A, X>(value())) : Option.<Either<A, X>>none() : Option.<Either<A, X>>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(new F<F<A, X>, Either<X, B>>() { public Either<X, B> f(final F<A, X> f) { return map(f); } }); } /** * 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 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 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 isLeft() ? single(value()) : List.<A>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 isLeft() ? some(value()) : Option.<A>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 (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 isLeft() ? Stream.single(value()) : Stream.<A>nil(); } /** * Projects an immutable collection of this projection. * * @return An immutable collection of this projection. */ public Collection<A> toCollection() { return toList().toCollection(); } } /** * A right projection of an either value. */ public 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 P1<String> err) { if (e.isRight()) //noinspection CastToConcreteClass return ((Right<A, B>) e).b; else throw error(err._1()); } /** * 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 P1<B> b) { return isRight() ? value() : b._1(); } /** * 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 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 (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 (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 isRight() ? new Right<A, X>(f.f(value())) : new Left<A, X>(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 isRight() ? f.f(value()) : new Left<A, X>(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.<B, Either<A, X>>constant(e)); } /** * 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 isRight() ? f.f(value()) ? Option.<Either<X, B>>some(new Right<X, B>(value())) : Option.<Either<X, B>>none() : Option.<Either<X, B>>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(new F<F<B, X>, Either<A, X>>() { public Either<A, X> f(final F<B, X> f) { return map(f); } }); } /** * 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 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 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 isRight() ? single(value()) : List.<B>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 isRight() ? some(value()) : Option.<B>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 (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 isRight() ? Stream.single(value()) : Stream.<B>nil(); } /** * Projects an immutable collection of this projection. * * @return An immutable collection of this projection. */ public Collection<B> toCollection() { return toList().toCollection(); } } /** * 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, B>(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 new F<A, Either<A, B>>() { public Either<A, B> f(final A a) { return left(a); } }; } /** * 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 new F<B, Either<A, B>>() { public Either<A, B> f(final B b) { return right(b); } }; } /** * 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<A, B>(b); } /** * @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 new F<F<A, X>, F<Either<A, B>, Either<X, B>>>() { public F<Either<A, B>, Either<X, B>> f(final F<A, X> axf) { return new F<Either<A, B>, Either<X, B>>() { public Either<X, B> f(final Either<A, B> e) { return 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 new F<F<B, X>, F<Either<A, B>, Either<A, X>>>() { public F<Either<A, B>, Either<A, X>> f(final F<B, X> axf) { return new F<Either<A, B>, Either<A, X>>() { public Either<A, X> f(final Either<A, B> e) { return 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) { final F<Either<A, B>, Either<A, B>> id = identity(); return e.left().bind(id); } /** * 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) { final F<Either<A, B>, Either<A, B>> id = identity(); return e.right().bind(id); } /** * 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() ? Either.<List<A>, X>left(List.<A>nil()) : a.head().left().bind(new F<A, Either<List<A>, X>>() { public Either<List<A>, X> f(final A aa) { return 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() ? Either.<X, List<B>>right(List.<B>nil()) : a.head().right().bind(new F<B, Either<X, List<B>>>() { public Either<X, List<B>> f(final B bb) { return sequenceRight(a.tail()).right().map(cons_(bb)); } }); } /** * 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.isLeft() ? e.left().value() : e.right().value(); } /** * 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 P1<B> right, final P1<A> left) { return c ? new Right<A, B>(right._1()) : new Left<A, B>(left._1()); } /** * 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(new F<Either<A, B>, F<List<A>, List<A>>>() { public F<List<A>, List<A>> f(final Either<A, B> e) { return new F<List<A>, List<A>>() { public List<A> f(final List<A> as) { return e.isLeft() ? as.cons(e.left().value()) : as; } }; } }, List.<A>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(new F<Either<A, B>, F<List<B>, List<B>>>() { public F<List<B>, List<B>> f(final Either<A, B> e) { return new F<List<B>, List<B>>() { public List<B> f(final List<B> bs) { return e.isRight() ? bs.cons(e.right().value()) : bs; } }; } }, List.<B>nil()); } public String toString() { return Show.eitherShow(Show.<A>anyShow(), Show.<B>anyShow()).showS(this); } }