view src/main/java/fj/data/Validation.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 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 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 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 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 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 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 <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 FailProjection<E, T> f() {
    return new FailProjection<E, T>(this);
  }

  /**
   * Returns an either projection of this validation.
   *
   * @return An either projection of this validation.
   */
  public 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 T successE(final P1<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 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 T orSuccess(final P1<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 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 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 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 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 <A> Validation<E, A> map(final F<T, A> f) {
    return isFail() ?
        Validation.<E, A>fail(fail()) :
        Validation.<E, A>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 <A> Validation<E, A> bind(final F<T, Validation<E, A>> f) {
    return isSuccess() ? f.f(success()) : Validation.<E, A>fail(fail());
  }

  /**
   * Anonymous bind through this validation.
   *
   * @param v The value to bind with.
   * @return A validation after binding.
   */
  public <A> Validation<E, A> sequence(final Validation<E, A> v) {
    return bind(Function.<T, Validation<E, A>>constant(v));
  }

  /**
   * 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 <A> Option<Validation<A, T>> filter(final F<T, Boolean> f) {
    return e.right().<A>filter(f).map(Validation.<A, T>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 <A> Validation<E, A> apply(final Validation<E, F<T, A>> v) {
    return v.bind(new F<F<T, A>, Validation<E, A>>() {
      public Validation<E, A> f(final F<T, A> f) {
        return map(f);
      }
    });
  }

  /**
   * 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 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 boolean exists(final F<T, Boolean> f) {
    return e.right().exists(f);
  }

  /**
   * 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 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 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 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 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 <A> Validation<E, A> accumapply(final Semigroup<E> s, final Validation<E, F<T, A>> v) {
    return isFail() ?
        Validation.<E, A>fail(v.isFail() ?
            s.sum(v.fail(), fail()) :
            fail()) :
        v.isFail() ?
            Validation.<E, A>fail(v.fail()) :
            Validation.<E, A>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 <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 <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 <A> Option<E> accumulate(final Semigroup<E> s, final Validation<E, A> va) {
    return accumulate(s, va, new F2<T, A, Unit>() {
      public Unit f(final T t, final A a) {
        return 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 <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 <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 <A, B> Option<E> accumulate(final Semigroup<E> s, final Validation<E, A> va, final Validation<E, B> vb) {
    return accumulate(s, va, vb, new F3<T, A, B, Unit>() {
      public Unit f(final T t, final A a, final B b) {
        return 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 <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 <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 <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, new F4<T, A, B, C, Unit>() {
      public Unit f(final T t, final A a, final B b, final C c) {
        return 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 <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 <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 <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, new F5<T, A, B, C, D, Unit>() {
      public Unit f(final T t, final A a, final B b, final C c, final D d) {
        return 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 <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 <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 <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, new F6<T, A, B, C, D, E$, Unit>() {
      public Unit f(final T t, final A a, final B b, final C c, final D d, final E$ e) {
        return 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 <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 <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 <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, new F7<T, A, B, C, D, E$, F$, Unit>() {
      public Unit f(final T t, final A a, final B b, final C c, final D d, final E$ e, final F$ f) {
        return 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 <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 <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 <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, new F8<T, A, B, C, D, E$, F$, G, Unit>() {
      public Unit f(final T t, final A a, final B b, final C c, final D d, final E$ e, final F$ f, final G g) {
        return 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 Iterator<T> iterator() {
    return toEither().right().iterator();
  }


    public Validation<List<E>, T> accumulate() {
        if (isFail()) {
            return Validation.fail(List.<E>single(fail()));
        } else {
            return Validation.success(success());
        }
    }

    public <B> Validation<List<E>, B> accumulate(F<T, B> f) {
        if (isFail()) {
            return Validation.fail(List.<E>single(fail()));
        } else {
            return Validation.success(f.f(success()));
        }
    }


    public <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 Validation.fail(list);
        } else {
            return Validation.success(f.f(success(), v2.success()));
        }
    }



    public <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.list(this, v2, v3));
        if (!list.isEmpty()) {
            return Validation.fail(list);
        } else {
            return Validation.success(f.f(success(), v2.success(), v3.success()));
        }
    }

    public <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.list(this, v2, v3, v4));
        if (!list.isEmpty()) {
            return Validation.fail(list);
        } else {
            return Validation.success(f.f(success(), v2.success(), v3.success(), v4.success()));
        }
    }

    public <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.list(this, v2, v3, v4, v5));
        if (!list.isEmpty()) {
            return Validation.fail(list);
        } else {
            return Validation.success(f.f(success(), v2.success(), v3.success(), v4.success(), v5.success()));
        }
    }


    public <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.list(this, v2, v3, v4, v5));
        if (!list.isEmpty()) {
            return Validation.fail(list);
        } else {
            return Validation.success(f.f(success(), v2.success(), v3.success(), v4.success(), v5.success(), v6.success()));
        }
    }

    public <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.list(this, v2, v3, v4, v5));
        if (!list.isEmpty()) {
            return Validation.fail(list);
        } else {
            return Validation.success(f.f(success(), v2.success(), v3.success(), v4.success(), v5.success(), v6.success(), v7.success()));
        }
    }

    public <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.list(this, v2, v3, v4, v5));
        if (!list.isEmpty()) {
            return Validation.fail(list);
        } else {
            return Validation.success(f.f(success(), v2.success(), v3.success(), v4.success(), v5.success(), v6.success(), v7.success(), v8.success()));
        }
    }



    public static <A, E> Validation<List<E>, List<A>> sequence(List<Validation<E, A>> list) {
        F2<Validation<E, A>, Validation<List<E>, List<A>>, Validation<List<E>, List<A>>> f2 = (v, acc) -> {
            if (acc.isFail() && v.isFail()) {
                return Validation.validation(acc.toEither().left().map(l -> l.cons(v.fail())));
            } else if (acc.isSuccess() && v.isSuccess()) {
                return acc.map(l -> l.cons(v.success()));
            } else {
                return acc;
            }
        };
        return list.foldRight(f2, Validation.success(List.nil()));
    }



    public static <A, E> List<E> fails(List<Validation<E, ?>> list) {
        return list.filter(v -> v.isFail()).map(v -> v.fail());
    }

    public static <A, E> List<A> successes(List<Validation<?, A>> list) {
        return list.filter(v -> v.isSuccess()).map(v -> v.success());
    }

  /**
   * A failing projection of a validation.
   */
  public 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 P1<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 P1<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.<A, T>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(new F<E, Validation<A, T>>() {
        public Validation<A, T> f(final E e) {
          return 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.<E, A>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(new F<F<E, A>, Validation<A, T>>() {
        public Validation<A, T> f(final F<E, A> f) {
          return map(f);
        }
      });
    }

    /**
     * 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 Validation<NonEmptyList<E>, T> nel() {
    return isSuccess() ?
        Validation.<NonEmptyList<E>, T>success(success()) :
        Validation.<NonEmptyList<E>, T>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, T>(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 new F<Either<E, T>, Validation<E, T>>() {
      public Validation<E, T> f(final Either<E, T> e) {
        return validation(e);
      }
    };
  }

  /**
   * 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 new F<Validation<E, T>, Either<E, T>>() {
      public Either<E, T> f(final Validation<E, T> v) {
        return v.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.<E, T>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.<E, T>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.<E, T>success(t) : Validation.<E, T>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 = new F<String, Validation<NumberFormatException, Byte>>() {
    public Validation<NumberFormatException, Byte> f(final String s) {
      return parseByte(s);
    }
  };

  /**
   * 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 = new F<String, Validation<NumberFormatException, Double>>() {
    public Validation<NumberFormatException, Double> f(final String s) {
      return parseDouble(s);
    }
  };

  /**
   * 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 = new F<String, Validation<NumberFormatException, Float>>() {
    public Validation<NumberFormatException, Float> f(final String s) {
      return parseFloat(s);
    }
  };

  /**
   * 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 = new F<String, Validation<NumberFormatException, Integer>>() {
    public Validation<NumberFormatException, Integer> f(final String s) {
      return parseInt(s);
    }
  };

  /**
   * 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 = new F<String, Validation<NumberFormatException, Long>>() {
    public Validation<NumberFormatException, Long> f(final String s) {
      return parseLong(s);
    }
  };

  /**
   * 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 = new F<String, Validation<NumberFormatException, Short>>() {
    public Validation<NumberFormatException, Short> f(final String s) {
      return parseShort(s);
    }
  };

    public String toString() {
        return Show.validationShow(Show.<E>anyShow(), Show.<T>anyShow()).showS(this);
    }




}