package fj.data; import fj.*; import fj.function.Effect1; import static fj.Function.curry; import static fj.P.p; import static fj.Unit.unit; import static fj.Bottom.error; import static fj.data.List.list; import java.util.Iterator; /** * Isomorphic to {@link Either} but has renamed functions and represents failure on the left and success on the right. * This type also has accumulating functions that accept a {@link Semigroup} for binding computation while keeping error * values * * @version %build.number% */ public class Validation<E, T> implements Iterable<T> { private final Either<E, T> e; protected Validation(final Either<E, T> e) { this.e = e; } /** * Returns <code>true</code> if this is a failure, <code>false</code> otherwise. * * @return <code>true</code> if this is a failure, <code>false</code> otherwise. */ public final boolean isFail() { return e.isLeft(); } /** * Returns <code>true</code> if this is a success, <code>false</code> otherwise. * * @return <code>true</code> if this is a success, <code>false</code> otherwise. */ public final boolean isSuccess() { return e.isRight(); } /** * Returns the failing value, or throws an error if there is no failing value. * * @return the failing value, or throws an error if there is no failing value. */ public final E fail() { if (isFail()) return e.left().value(); else throw error("Validation: fail on success value"); } /** * Returns the success value, or throws an error if there is no success value. * * @return the success value, or throws an error if there is no success value. */ public final T success() { if (isSuccess()) return e.right().value(); else throw error("Validation: success on fail value"); } /** * The catamorphism for validation. Folds over this validation breaking into left or right. * * @param fail The function to call if this failed. * @param success The function to call if this succeeded. * @return The reduced value. */ public final <X> X validation(final F<E, X> fail, final F<T, X> success) { return e.either(fail, success); } /** * Returns a failing projection of this validation. * * @return a failing projection of this validation. */ public final FailProjection<E, T> f() { return new FailProjection<>(this); } /** * Returns an either projection of this validation. * * @return An either projection of this validation. */ public final Either<E, T> toEither() { return e; } /** * Returns the success value or fails with the given error message. * * @param err The error message to fail with. * @return The success value. */ public final T successE(final F0<String> err) { return e.right().valueE(err); } /** * Returns the success value or fails with the given error message. * * @param err The error message to fail with. * @return The success value. */ public final T successE(final String err) { return e.right().valueE(p(err)); } /** * Returns the success value or the given value. * * @param t The value to return if this is failure. * @return The success value or the given value. */ public final T orSuccess(final F0<T> t) { return e.right().orValue(t); } /** * Returns the success value or the given value. * * @param t The value to return if this is failure. * @return The success value or the given value. */ public final T orSuccess(final T t) { return e.right().orValue(p(t)); } /** * The success value or the application of the given function to the failing value. * * @param f The function to execute on the failing value. * @return The success value or the application of the given function to the failing value. */ public final T on(final F<E, T> f) { return e.right().on(f); } /** * Executes a side-effect on the success value if there is one. * * @param f The side-effect to execute. * @return The unit value. */ public final Unit foreach(final F<T, Unit> f) { return e.right().foreach(f); } /** * Executes a side-effect on the success value if there is one. * * @param f The side-effect to execute. */ public final void foreachDoEffect(final Effect1<T> f) { e.right().foreachDoEffect(f); } /** * Maps the given function across the success side of this validation. * * @param f The function to map. * @return A new validation with the function mapped. */ @SuppressWarnings("unchecked") public final <A> Validation<E, A> map(final F<T, A> f) { return isFail() ? Validation.fail(fail()) : Validation.success(f.f(success())); } /** * Binds the given function across this validation's success value if it has one. * * @param f The function to bind across this validation. * @return A new validation value after binding. */ @SuppressWarnings("unchecked") public final <A> Validation<E, A> bind(final F<T, Validation<E, A>> f) { return isSuccess() ? f.f(success()) : Validation.fail(fail()); } /** * Anonymous bind through this validation. * * @param v The value to bind with. * @return A validation after binding. */ public final <A> Validation<E, A> sequence(final Validation<E, A> v) { return bind(Function.constant(v)); } /** * If list contains a failure, returns a failure of the reduction of * all the failures using the semigroup, otherwise returns the successful list. */ public static <E, A> Validation<E, List<A>> sequence(final Semigroup<E> s, final List<Validation<E, A>> list) { if (list.exists(Validation::isFail)) { return Validation.fail(list.filter(Validation::isFail).map(v -> v.fail()).foldLeft1((F2<E, E, E>) s::sum)); } else { return success(list.foldLeft((List<A> acc, Validation<E, A> v) -> acc.cons(v.success()), List.nil()).reverse()); } } /** * Returns <code>None</code> if this is a failure or if the given predicate <code>p</code> does not hold for the * success value, otherwise, returns a success in <code>Some</code>. * * @param f The predicate function to test on this success value. * @return <code>None</code> if this is a failure or if the given predicate <code>p</code> does not hold for the * success value, otherwise, returns a success in <code>Some</code>. */ public final <A> Option<Validation<A, T>> filter(final F<T, Boolean> f) { return e.right().<A>filter(f).map(Validation.validation()); } /** * Function application on the success value. * * @param v The validation of the function to apply on the success value. * @return The result of function application in validation. */ public final <A> Validation<E, A> apply(final Validation<E, F<T, A>> v) { return v.bind(this::map); } /** * Returns <code>true</code> if this is a failure or returns the result of the application of the given * function to the success value. * * @param f The predicate function to test on this success value. * @return <code>true</code> if this is a failure or returns the result of the application of the given * function to the success value. */ public final boolean forall(final F<T, Boolean> f) { return e.right().forall(f); } /** * Returns <code>false</code> if this is a failure or returns the result of the application of the given * function to the success value. * * @param f The predicate function to test on this success value. * @return <code>false</code> if this is a failure or returns the result of the application of the given * function to the success value. */ public final boolean exists(final F<T, Boolean> f) { return e.right().exists(f); } @Override public final boolean equals(Object other) { return Equal.equals0(Validation.class, this, other, () -> Equal.validationEqual(Equal.anyEqual(), Equal.anyEqual())); } @Override public final int hashCode() { return Hash.validationHash(Hash.<E>anyHash(), Hash.<T>anyHash()).hash(this); } /** * Returns a single element list if this is a success value, otherwise an empty list. * * @return A single element list if this is a success value, otherwise an empty list. */ public final List<T> toList() { return e.right().toList(); } /** * Returns the success value in <code>Some</code> if there is one, otherwise <code>None</code>. * * @return The success value in <code>Some</code> if there is one, otherwise <code>None</code>. */ public final Option<T> toOption() { return e.right().toOption(); } /** * Returns a single element array if this is a success value, otherwise an empty list. * * @return A single element array if this is a success value, otherwise an empty list. */ public final Array<T> toArray() { return e.right().toArray(); } /** * Returns a single element stream if this is a success value, otherwise an empty list. * * @return A single element stream if this is a success value, otherwise an empty list. */ public final Stream<T> toStream() { return e.right().toStream(); } /** * Function application on the successful side of this validation, or accumulating the errors on the failing side * using the given semigroup should one or more be encountered. * * @param s The semigroup to accumulate errors with if * @param v The validating function to apply. * @return A failing validation if this or the given validation failed (with errors accumulated if both) or a * succeeding validation if both succeeded. */ @SuppressWarnings("unchecked") public final <A> Validation<E, A> accumapply(final Semigroup<E> s, final Validation<E, F<T, A>> v) { return isFail() ? Validation.fail(v.isFail() ? s.sum(v.fail(), fail()) : fail()) : v.isFail() ? Validation.fail(v.fail()) : Validation.success(v.success().f(success())); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B> Validation<E, B> accumulate(final Semigroup<E> s, final Validation<E, A> va, final F<T, F<A, B>> f) { return va.accumapply(s, map(f)); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B> Validation<E, B> accumulate(final Semigroup<E> s, final Validation<E, A> va, final F2<T, A, B> f) { return va.accumapply(s, map(curry(f))); } /** * Accumulates errors anonymously. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @return A <code>Some</code> if one or more validations failed (accumulated with the semigroup), otherwise, * <code>None</code>. */ public final <A> Option<E> accumulate(final Semigroup<E> s, final Validation<E, A> va) { return accumulate(s, va, (t, a) -> unit()).f().toOption(); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B, C> Validation<E, C> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final F<T, F<A, F<B, C>>> f) { return vb.accumapply(s, accumulate(s, va, f)); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B, C> Validation<E, C> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final F3<T, A, B, C> f) { return vb.accumapply(s, accumulate(s, va, curry(f))); } /** * Accumulates errors anonymously. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @return A <code>Some</code> if one or more validations failed (accumulated with the semigroup), otherwise, * <code>None</code>. */ public final <A, B> Option<E> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb) { return accumulate(s, va, vb, (t, a, b) -> unit()).f().toOption(); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B, C, D> Validation<E, D> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final F<T, F<A, F<B, F<C, D>>>> f) { return vc.accumapply(s, accumulate(s, va, vb, f)); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B, C, D> Validation<E, D> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final F4<T, A, B, C, D> f) { return vc.accumapply(s, accumulate(s, va, vb, curry(f))); } /** * Accumulates errors anonymously. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @return A <code>Some</code> if one or more validations failed (accumulated with the semigroup), otherwise, * <code>None</code>. */ public final <A, B, C> Option<E> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc) { return accumulate(s, va, vb, vc, (t, a, b, c) -> unit()).f().toOption(); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param vd The fifth validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B, C, D, E$> Validation<E, E$> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final Validation<E, D> vd, final F<T, F<A, F<B, F<C, F<D, E$>>>>> f) { return vd.accumapply(s, accumulate(s, va, vb, vc, f)); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param vd The fifth validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B, C, D, E$> Validation<E, E$> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final Validation<E, D> vd, final F5<T, A, B, C, D, E$> f) { return vd.accumapply(s, accumulate(s, va, vb, vc, curry(f))); } /** * Accumulates errors anonymously. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param vd The fifth validation to accumulate errors with if it failed. * @return A <code>Some</code> if one or more validations failed (accumulated with the semigroup), otherwise, * <code>None</code>. */ public final <A, B, C, D> Option<E> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final Validation<E, D> vd) { return accumulate(s, va, vb, vc, vd, (t, a, b, c, d) -> unit()).f().toOption(); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param vd The fifth validation to accumulate errors with if it failed. * @param ve The sixth validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B, C, D, E$, F$> Validation<E, F$> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final Validation<E, D> vd, final Validation<E, E$> ve, final F<T, F<A, F<B, F<C, F<D, F<E$, F$>>>>>> f) { return ve.accumapply(s, accumulate(s, va, vb, vc, vd, f)); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param vd The fifth validation to accumulate errors with if it failed. * @param ve The sixth validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B, C, D, E$, F$> Validation<E, F$> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final Validation<E, D> vd, final Validation<E, E$> ve, final F6<T, A, B, C, D, E$, F$> f) { return ve.accumapply(s, accumulate(s, va, vb, vc, vd, curry(f))); } /** * Accumulates errors anonymously. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param vd The fifth validation to accumulate errors with if it failed. * @param ve The sixth validation to accumulate errors with if it failed. * @return A <code>Some</code> if one or more validations failed (accumulated with the semigroup), otherwise, * <code>None</code>. */ public final <A, B, C, D, E$> Option<E> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final Validation<E, D> vd, final Validation<E, E$> ve) { return accumulate(s, va, vb, vc, vd, ve, (t, a, b, c, d, e1) -> unit()).f().toOption(); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param vd The fifth validation to accumulate errors with if it failed. * @param ve The sixth validation to accumulate errors with if it failed. * @param vf The seventh validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B, C, D, E$, F$, G> Validation<E, G> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final Validation<E, D> vd, final Validation<E, E$> ve, final Validation<E, F$> vf, final F<T, F<A, F<B, F<C, F<D, F<E$, F<F$, G>>>>>>> f) { return vf.accumapply(s, accumulate(s, va, vb, vc, vd, ve, f)); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param vd The fifth validation to accumulate errors with if it failed. * @param ve The sixth validation to accumulate errors with if it failed. * @param vf The seventh validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B, C, D, E$, F$, G> Validation<E, G> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final Validation<E, D> vd, final Validation<E, E$> ve, final Validation<E, F$> vf, final F7<T, A, B, C, D, E$, F$, G> f) { return vf.accumapply(s, accumulate(s, va, vb, vc, vd, ve, curry(f))); } /** * Accumulates errors anonymously. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param vd The fifth validation to accumulate errors with if it failed. * @param ve The sixth validation to accumulate errors with if it failed. * @param vf The seventh validation to accumulate errors with if it failed. * @return A <code>Some</code> if one or more validations failed (accumulated with the semigroup), otherwise, * <code>None</code>. */ public final <A, B, C, D, E$, F$> Option<E> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final Validation<E, D> vd, final Validation<E, E$> ve, final Validation<E, F$> vf) { return accumulate(s, va, vb, vc, vd, ve, vf, (t, a, b, c, d, e1, f) -> unit()).f().toOption(); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param vd The fifth validation to accumulate errors with if it failed. * @param ve The sixth validation to accumulate errors with if it failed. * @param vf The seventh validation to accumulate errors with if it failed. * @param vg The eighth validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B, C, D, E$, F$, G, H> Validation<E, H> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final Validation<E, D> vd, final Validation<E, E$> ve, final Validation<E, F$> vf, final Validation<E, G> vg, final F<T, F<A, F<B, F<C, F<D, F<E$, F<F$, F<G, H>>>>>>>> f) { return vg.accumapply(s, accumulate(s, va, vb, vc, vd, ve, vf, f)); } /** * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies * the given function if all succeeded and returns that value on the successful side. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param vd The fifth validation to accumulate errors with if it failed. * @param ve The sixth validation to accumulate errors with if it failed. * @param vf The seventh validation to accumulate errors with if it failed. * @param vg The eighth validation to accumulate errors with if it failed. * @param f The function to apply if all validations have succeeded. * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if * one or more failed. */ public final <A, B, C, D, E$, F$, G, H> Validation<E, H> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final Validation<E, D> vd, final Validation<E, E$> ve, final Validation<E, F$> vf, final Validation<E, G> vg, final F8<T, A, B, C, D, E$, F$, G, H> f) { return vg.accumapply(s, accumulate(s, va, vb, vc, vd, ve, vf, curry(f))); } /** * Accumulates errors anonymously. * * @param s The semigroup to accumulate errors with if one or more validations fail. * @param va The second validation to accumulate errors with if it failed. * @param vb The third validation to accumulate errors with if it failed. * @param vc The fourth validation to accumulate errors with if it failed. * @param vd The fifth validation to accumulate errors with if it failed. * @param ve The sixth validation to accumulate errors with if it failed. * @param vf The seventh validation to accumulate errors with if it failed. * @param vg The eighth validation to accumulate errors with if it failed. * @return A <code>Some</code> if one or more validations failed (accumulated with the semigroup), otherwise, * <code>None</code>. */ public final <A, B, C, D, E$, F$, G> Option<E> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb, final Validation<E, C> vc, final Validation<E, D> vd, final Validation<E, E$> ve, final Validation<E, F$> vf, final Validation<E, G> vg) { return accumulate(s, va, vb, vc, vd, ve, vf, vg, (t, a, b, c, d, e1, f, g) -> unit()).f().toOption(); } /** * Returns an iterator for this validation. This method exists to permit the use in a <code>for</code>-each loop. * * @return A iterator for this validation. */ public final Iterator<T> iterator() { return toEither().right().iterator(); } public final Validation<List<E>, T> accumulate() { if (isFail()) { return fail(List.single(fail())); } else { return success(success()); } } public final <B> Validation<List<E>, B> accumulate(F<T, B> f) { if (isFail()) { return fail(List.single(fail())); } else { return success(f.f(success())); } } public final <B, C> Validation<List<E>, C> accumulate(Validation<E, B> v2, F2<T, B, C> f) { List<E> list = List.nil(); if (isFail()) { list = list.cons(fail()); } if (v2.isFail()) { list = list.cons(v2.fail()); } if (!list.isEmpty()) { return fail(list); } else { return success(f.f(success(), v2.success())); } } public final <B, C, D> Validation<List<E>, D> accumulate(Validation<E, B> v2, Validation<E, C> v3, F3<T, B, C, D> f) { List<E> list = fails(list(this, v2, v3)); if (!list.isEmpty()) { return fail(list); } else { return success(f.f(success(), v2.success(), v3.success())); } } public final <B, C, D, $E> Validation<List<E>, $E> accumulate(Validation<E, B> v2, Validation<E, C> v3, Validation<E, D> v4, F4<T, B, C, D, $E> f) { List<E> list = fails(list(this, v2, v3, v4)); if (!list.isEmpty()) { return fail(list); } else { return success(f.f(success(), v2.success(), v3.success(), v4.success())); } } public final <B, C, D, $E, $F> Validation<List<E>, $F> accumulate(Validation<E, B> v2, Validation<E, C> v3, Validation<E, D> v4, Validation<E, $E> v5, F5<T, B, C, D, $E, $F> f) { List<E> list = fails(list(this, v2, v3, v4, v5)); if (!list.isEmpty()) { return fail(list); } else { return success(f.f(success(), v2.success(), v3.success(), v4.success(), v5.success())); } } public final <B, C, D, $E, $F, G> Validation<List<E>, G> accumulate(Validation<E, B> v2, Validation<E, C> v3, Validation<E, D> v4, Validation<E, $E> v5, Validation<E, $F> v6, F6<T, B, C, D, $E, $F, G> f) { List<E> list = fails(list(this, v2, v3, v4, v5)); if (!list.isEmpty()) { return fail(list); } else { return success(f.f(success(), v2.success(), v3.success(), v4.success(), v5.success(), v6.success())); } } public final <B, C, D, $E, $F, G, H> Validation<List<E>, H> accumulate(Validation<E, B> v2, Validation<E, C> v3, Validation<E, D> v4, Validation<E, $E> v5, Validation<E, $F> v6, Validation<E, G> v7, F7<T, B, C, D, $E, $F, G, H> f) { List<E> list = fails(list(this, v2, v3, v4, v5)); if (!list.isEmpty()) { return fail(list); } else { return success(f.f(success(), v2.success(), v3.success(), v4.success(), v5.success(), v6.success(), v7.success())); } } public final <B, C, D, $E, $F, G, H, I> Validation<List<E>, I> accumulate(Validation<E, B> v2, Validation<E, C> v3, Validation<E, D> v4, Validation<E, $E> v5, Validation<E, $F> v6, Validation<E, G> v7, Validation<E, H> v8, F8<T, B, C, D, $E, $F, G, H, I> f) { List<E> list = fails(list(this, v2, v3, v4, v5)); if (!list.isEmpty()) { return fail(list); } else { return success(f.f(success(), v2.success(), v3.success(), v4.success(), v5.success(), v6.success(), v7.success(), v8.success())); } } /** * If the list contains a failure, returns a Validation of the list of * fails in the list, otherwise returns a successful Validation with * the list of successful values. Does not accumulate the failures into a * single failure using a semigroup. */ public static <A, E> Validation<List<E>, List<A>> sequenceNonCumulative(List<Validation<E, A>> list) { if (list.exists(Validation::isFail)) { F2<List<E>, Validation<E, A>, List<E>> f = (acc, v) -> acc.cons(v.fail()); return fail(list.filter(Validation::isFail).foldLeft(f, List.nil()).reverse()); } else { F2<List<A>, Validation<E, A>, List<A>> f = (acc, v) -> acc.cons(v.success()); return success(list.filter(Validation::isSuccess).foldLeft(f, List.nil()).reverse()); } } public final <C> List<Validation<E, C>> traverseList(F<T, List<C>> f){ return isSuccess() ? f.f(success()).map(Validation::success) : List.iterableList(fail(e.left().value())); } public final <C> Stream<Validation<E, C>> traverseStream(F<T, Stream<C>> f){ return isSuccess() ? f.f(success()).map(Validation::success) : Stream.iterableStream(fail(e.left().value())); } public final <C> Option<Validation<E, C>> traverseOption(F<T, Option<C>> f){ return isSuccess() ? f.f(success()).map(Validation::success) : Option.some(fail(e.left().value())); } public final <C> IO<Validation<E, C>> traverseIO(F<T, IO<C>> f){ return isSuccess() ? IOFunctions.map(f.f(success()), Validation::success) : IOFunctions.unit(fail(e.left().value())); } public final <C> P1<Validation<E, C>> traverseP1(F<T, P1<C>> f){ return isSuccess() ? f.f(success()).map(Validation::success) : p(fail(e.left().value())); } public static <A, E> List<E> fails(List<Validation<E, ?>> list) { return list.filter(Validation::isFail).map(v -> v.fail()); } public static <A, E> List<A> successes(List<Validation<?, A>> list) { return list.filter(Validation::isSuccess).map(v -> v.success()); } /** * A failing projection of a validation. */ public static final class FailProjection<E, T> implements Iterable<E> { private final Validation<E, T> v; private FailProjection(final Validation<E, T> v) { this.v = v; } /** * Returns the underlying validation. * * @return The underlying validation. */ public Validation<E, T> validation() { return v; } /** * Returns the failing value or fails with the given error message. * * @param err The error message to fail with. * @return The failing value. */ public E failE(final F0<String> err) { return v.toEither().left().valueE(err); } /** * Returns the failing value or fails with the given error message. * * @param err The error message to fail with. * @return The failing value. */ public E failE(final String err) { return failE(p(err)); } /** * Returns the failing value or the given value. * * @param e The value to return if this is success. * @return The failing value or the given value. */ public E orFail(final F0<E> e) { return v.toEither().left().orValue(e); } /** * Returns the failing value or the given value. * * @param e The value to return if this is success. * @return The failing value or the given value. */ public E orFail(final E e) { return orFail(p(e)); } /** * The failing value or the application of the given function to the success value. * * @param f The function to execute on the success value. * @return The failing value or the application of the given function to the success value. */ public E on(final F<T, E> f) { return v.toEither().left().on(f); } /** * Executes a side-effect on the failing value if there is one. * * @param f The side-effect to execute. * @return The unit value. */ public Unit foreach(final F<E, Unit> f) { return v.toEither().left().foreach(f); } /** * Executes a side-effect on the failing value if there is one. * * @param f The side-effect to execute. */ public void foreachDoEffect(final Effect1<E> f) { v.toEither().left().foreachDoEffect(f); } /** * Maps the given function across the failing side of this validation. * * @param f The function to map. * @return A new validation with the function mapped. */ public <A> Validation<A, T> map(final F<E, A> f) { return Validation.validation(v.toEither().left().map(f)); } /** * Binds the given function across this validation's failing value if it has one. * * @param f The function to bind across this validation. * @return A new validation value after binding. */ public <A> Validation<A, T> bind(final F<E, Validation<A, T>> f) { return v.isFail() ? f.f(v.fail()) : Validation.success(v.success()); } /** * Performs a bind across the validation, but ignores the element value in the function. * * @param v The validation value to apply in the final join. * @return A new validation value after the final join. */ public <A> Validation<A, T> sequence(final Validation<A, T> v) { return bind(e1 -> v); } /** * Returns <code>None</code> if this is a success or if the given predicate <code>p</code> does not hold for the * failing value, otherwise, returns a fail in <code>Some</code>. * * @param f The predicate function to test on this failing value. * @return <code>None</code> if this is a success or if the given predicate <code>p</code> does not hold for the * failing value, otherwise, returns a fail in <code>Some</code>. */ public <A> Option<Validation<E, A>> filter(final F<E, Boolean> f) { return v.toEither().left().<A>filter(f).map(Validation.validation()); } /** * Function application on the failing value. * * @param v The validation of the function to apply on the failing value. * @return The result of function application in validation. */ public <A> Validation<A, T> apply(final Validation<F<E, A>, T> v) { return v.f().bind(this::map); } /** * Returns <code>true</code> if this is a success or returns the result of the application of the given * function to the failing value. * * @param f The predicate function to test on this failing value. * @return <code>true</code> if this is a success or returns the result of the application of the given * function to the failing value. */ public boolean forall(final F<E, Boolean> f) { return v.toEither().left().forall(f); } /** * Returns <code>false</code> if this is a success or returns the result of the application of the given * function to the failing value. * * @param f The predicate function to test on this failing value. * @return <code>false</code> if this is a success or returns the result of the application of the given * function to the failing value. */ public boolean exists(final F<E, Boolean> f) { return v.toEither().left().exists(f); } /** * Returns a single element list if this is a failing value, otherwise an empty list. * * @return A single element list if this is a failing value, otherwise an empty list. */ public List<E> toList() { return v.toEither().left().toList(); } /** * Returns the failing value in <code>Some</code> if there is one, otherwise <code>None</code>. * * @return The failing value in <code>Some</code> if there is one, otherwise <code>None</code>. */ public Option<E> toOption() { return v.toEither().left().toOption(); } /** * Returns a single element array if this is a failing value, otherwise an empty list. * * @return A single element array if this is a failing value, otherwise an empty list. */ public Array<E> toArray() { return v.toEither().left().toArray(); } /** * Returns a single element stream if this is a failing value, otherwise an empty list. * * @return A single element stream if this is a failing value, otherwise an empty list. */ public Stream<E> toStream() { return v.toEither().left().toStream(); } /** * 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<E> iterator() { return v.toEither().left().iterator(); } } /** * Puts this validation's failing value in a non-empty list if there is one. * * @return A validation with its failing value in a non-empty list if there is one. */ @SuppressWarnings("unchecked") public final Validation<NonEmptyList<E>, T> nel() { return isSuccess() ? Validation.success(success()) : Validation.fail(NonEmptyList.nel(fail())); } /** * Construct a validation using the given either value. * * @param e The either value to construct a validation with. * @return A validation using the given either value. */ public static <E, T> Validation<E, T> validation(final Either<E, T> e) { return new Validation<>(e); } /** * Returns a function that constructs a validation with an either. * * @return A function that constructs a validation with an either. */ public static <E, T> F<Either<E, T>, Validation<E, T>> validation() { return Validation::validation; } /** * Returns a function that constructs an either with a validation. * * @return A function that constructs an either with a validation. */ public static <E, T> F<Validation<E, T>, Either<E, T>> either() { return Validation::toEither; } /** * Returns a succeeding validation containing the given value. * * @param t The value to use in the succeeding validation. * @return A succeeding validation containing the given value. */ public static <E, T> Validation<E, T> success(final T t) { return validation(Either.right(t)); } /** * Returns a failing validation containing the given value. * * @param e The value to use in the failing validation. * @return A failing validation containing the given value. */ public static <E, T> Validation<E, T> fail(final E e) { return validation(Either.left(e)); } /** * Returns a failing validation containing a non-empty list that contains the given value. * * @param e The value to use in a non-empty list for the failing validation. * @return A failing validation containing a non-empty list that contains the given value. */ public static <E, T> Validation<NonEmptyList<E>, T> failNEL(final E e) { return fail(NonEmptyList.nel(e)); } /** * Returns a validation based on a boolean condition. If the condition is <code>true</code>, the validation succeeds, * otherwise it fails. * * @param c The condition to base the returned validation on. * @param e The failing value to use if the condition is <code>false</code>. * @param t The succeeding value to use if the condition is <code>true</code>. * @return A validation based on a boolean condition. */ public static <E, T> Validation<E, T> condition(final boolean c, final E e, final T t) { return c ? Validation.success(t) : Validation.fail(e); } /** * Parses the given string into a byte. * * @param s The string to parse. * @return A successfully parse byte or a failing exception. */ public static Validation<NumberFormatException, Byte> parseByte(final String s) { try { return success(Byte.parseByte(s)); } catch (NumberFormatException e) { return fail(e); } } /** * A function that parses a string into a byte. */ public static final F<String, Validation<NumberFormatException, Byte>> parseByte = Validation::parseByte; /** * Parses the given string into a double. * * @param s The string to parse. * @return A successfully parse double or a failing exception. */ public static Validation<NumberFormatException, Double> parseDouble(final String s) { try { return success(Double.parseDouble(s)); } catch (NumberFormatException e) { return fail(e); } } /** * A function that parses a string into a double. */ public static final F<String, Validation<NumberFormatException, Double>> parseDouble = Validation::parseDouble; /** * Parses the given string into a float. * * @param s The string to parse. * @return A successfully parse float or a failing exception. */ public static Validation<NumberFormatException, Float> parseFloat(final String s) { try { return success(Float.parseFloat(s)); } catch (NumberFormatException e) { return fail(e); } } /** * A function that parses a string into a float. */ public static final F<String, Validation<NumberFormatException, Float>> parseFloat = Validation::parseFloat; /** * Parses the given string into a integer. * * @param s The string to parse. * @return A successfully parse integer or a failing exception. */ public static Validation<NumberFormatException, Integer> parseInt(final String s) { try { return success(Integer.parseInt(s)); } catch (NumberFormatException e) { return fail(e); } } /** * A function that parses a string into an integer. */ public static final F<String, Validation<NumberFormatException, Integer>> parseInt = Validation::parseInt; /** * Parses the given string into a long. * * @param s The string to parse. * @return A successfully parse long or a failing exception. */ public static Validation<NumberFormatException, Long> parseLong(final String s) { try { return success(Long.parseLong(s)); } catch (NumberFormatException e) { return fail(e); } } /** * A function that parses a string into a long. */ public static final F<String, Validation<NumberFormatException, Long>> parseLong = Validation::parseLong; /** * Parses the given string into a short. * * @param s The string to parse. * @return A successfully parse short or a failing exception. */ public static Validation<NumberFormatException, Short> parseShort(final String s) { try { return success(Short.parseShort(s)); } catch (NumberFormatException e) { return fail(e); } } /** * A function that parses a string into a short. */ public static final F<String, Validation<NumberFormatException, Short>> parseShort = Validation::parseShort; /** * Partitions the list into the list of fails and the list of successes */ public static <A, B> P2<List<A>, List<B>> partition(List<Validation<A, B>> list) { return p( list.filter(Validation::isFail).map(v -> v.fail()), list.filter(Validation::isSuccess).map(v -> v.success()) ); } @Override public final String toString() { return Show.validationShow(Show.<E>anyShow(), Show.<T>anyShow()).showS(this); } }