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

fj.data.Validation Maven / Gradle / Ivy

Go to download

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

There is a newer version: 5.0
Show newest version
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 implements Iterable {
  private final Either e;

  protected Validation(final Either e) {
    this.e = e;
  }

  /**
   * Returns true if this is a failure, false otherwise.
   *
   * @return true if this is a failure, false otherwise.
   */
  public final boolean isFail() {
    return e.isLeft();
  }

  /**
   * Returns true if this is a success, false otherwise.
   *
   * @return true if this is a success, false 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 validation(final F fail, final F success) {
    return e.either(fail, success);
  }

  /**
   * Returns a failing projection of this validation.
   *
   * @return a failing projection of this validation.
   */
  public final FailProjection f() {
    return new FailProjection<>(this);
  }

  /**
   * Returns an either projection of this validation.
   *
   * @return An either projection of this validation.
   */
  public final Either 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 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) {
    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 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 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 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  Validation map(final F 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  Validation bind(final F> 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  Validation sequence(final Validation 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  Validation> sequence(final Semigroup s, final List> list) {
    if (list.exists(Validation::isFail)) {
      return Validation.fail(list.filter(Validation::isFail).map(v -> v.fail()).foldLeft1((F2) s::sum));
    } else {
      return success(list.foldLeft((List acc, Validation v) -> acc.cons(v.success()), List.nil()).reverse());
    }
  }

  /**
   * Returns None if this is a failure or if the given predicate p does not hold for the
   * success value, otherwise, returns a success in Some.
   *
   * @param f The predicate function to test on this success value.
   * @return None if this is a failure or if the given predicate p does not hold for the
   *         success value, otherwise, returns a success in Some.
   */
  public final  Option> filter(final F f) {
    return e.right().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  Validation apply(final Validation> v) {
    return v.bind(this::map);
  }

  /**
   * Returns true 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 true 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 f) {
    return e.right().forall(f);
  }

  /**
   * Returns false 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 false 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 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.anyHash(), Hash.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 toList() {
    return e.right().toList();
  }

  /**
   * Returns the success value in Some if there is one, otherwise None.
   *
   * @return The success value in Some if there is one, otherwise None.
   */
  public final Option 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 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 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  Validation accumapply(final Semigroup s, final Validation> 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  Validation accumulate(final Semigroup s, final Validation va, final F> 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  Validation accumulate(final Semigroup s, final Validation va, final F2 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 Some if one or more validations failed (accumulated with the semigroup), otherwise,
   *         None.
   */
  public final  Option accumulate(final Semigroup s, final Validation 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  Validation accumulate(final Semigroup s, final Validation va,
                                                     final Validation vb, final F>> 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  Validation accumulate(final Semigroup s, final Validation va,
                                                     final Validation vb, final F3 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 Some if one or more validations failed (accumulated with the semigroup), otherwise,
   *         None.
   */
  public final  Option accumulate(final Semigroup s, final Validation va, final Validation 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  Validation accumulate(final Semigroup s, final Validation va,
                                                        final Validation vb, final Validation vc,
                                                        final F>>> 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  Validation accumulate(final Semigroup s, final Validation va,
                                                        final Validation vb, final Validation vc,
                                                        final F4 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 Some if one or more validations failed (accumulated with the semigroup), otherwise,
   *         None.
   */
  public final  Option accumulate(final Semigroup s, final Validation va, final Validation vb,
                                              final Validation 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  Validation accumulate(final Semigroup s, final Validation va,
                                                             final Validation vb, final Validation vc,
                                                             final Validation vd,
                                                             final F>>>> 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  Validation accumulate(final Semigroup s, final Validation va,
                                                             final Validation vb, final Validation vc,
                                                             final Validation vd, final F5 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 Some if one or more validations failed (accumulated with the semigroup), otherwise,
   *         None.
   */
  public final  Option accumulate(final Semigroup s, final Validation va, final Validation vb,
                                                 final Validation vc, final Validation 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  Validation accumulate(final Semigroup s, final Validation va,
                                                                 final Validation vb, final Validation vc,
                                                                 final Validation vd, final Validation ve,
                                                                 final 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  Validation accumulate(final Semigroup s, final Validation va,
                                                                 final Validation vb, final Validation vc,
                                                                 final Validation vd, final Validation ve,
                                                                 final F6 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 Some if one or more validations failed (accumulated with the semigroup), otherwise,
   *         None.
   */
  public final  Option accumulate(final Semigroup s, final Validation va,
                                                     final Validation vb, final Validation vc,
                                                     final Validation vd, final Validation 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  Validation accumulate(final Semigroup s, final Validation va,
                                                                   final Validation vb, final Validation vc,
                                                                   final Validation vd, final Validation ve,
                                                                   final Validation vf,
                                                                   final F>>>>>> 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  Validation accumulate(final Semigroup s, final Validation va,
                                                                   final Validation vb, final Validation vc,
                                                                   final Validation vd, final Validation ve,
                                                                   final Validation vf,
                                                                   final F7 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 Some if one or more validations failed (accumulated with the semigroup), otherwise,
   *         None.
   */
  public final  Option accumulate(final Semigroup s, final Validation va,
                                                         final Validation vb, final Validation vc,
                                                         final Validation vd, final Validation ve,
                                                         final Validation 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  Validation accumulate(final Semigroup s, final Validation va,
                                                                      final Validation vb, final Validation vc,
                                                                      final Validation vd, final Validation ve,
                                                                      final Validation vf, final Validation vg,
                                                                      final F>>>>>>> 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  Validation accumulate(final Semigroup s, final Validation va,
                                                                      final Validation vb, final Validation vc,
                                                                      final Validation vd, final Validation ve,
                                                                      final Validation vf, final Validation vg,
                                                                      final F8 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 Some if one or more validations failed (accumulated with the semigroup), otherwise,
   *         None.
   */
  public final  Option accumulate(final Semigroup s, final Validation va,
                                                            final Validation vb, final Validation vc,
                                                            final Validation vd, final Validation ve,
                                                            final Validation vf, final Validation 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 for-each loop.
   *
   * @return A iterator for this validation.
   */
  public final Iterator iterator() {
    return toEither().right().iterator();
  }


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

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


    public final  Validation, C> accumulate(Validation v2, F2 f) {
        List 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  Validation, D> accumulate(Validation v2, Validation v3, F3 f) {
        List list = fails(list(this, v2, v3));
        if (!list.isEmpty()) {
            return fail(list);
        } else {
            return success(f.f(success(), v2.success(), v3.success()));
        }
    }

    public final  Validation, $E> accumulate(Validation v2, Validation v3, Validation v4, F4 f) {
        List 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  Validation, $F> accumulate(Validation v2, Validation v3, Validation v4, Validation v5, F5 f) {
        List 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  Validation, G> accumulate(Validation v2, Validation v3, Validation v4, Validation v5, Validation v6, F6 f) {
        List 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  Validation, H> accumulate(Validation v2, Validation v3, Validation v4, Validation v5, Validation v6, Validation v7, F7 f) {
        List 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  Validation, I> accumulate(Validation v2, Validation v3, Validation v4, Validation v5, Validation v6, Validation v7, Validation v8, F8 f) {
        List 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  Validation, List> sequenceNonCumulative(List> list) {
      if (list.exists(Validation::isFail)) {
        F2, Validation, List> f = (acc, v) -> acc.cons(v.fail());
        return fail(list.filter(Validation::isFail).foldLeft(f, List.nil()).reverse());
      } else {
        F2, Validation, List> f = (acc, v) -> acc.cons(v.success());
        return success(list.filter(Validation::isSuccess).foldLeft(f, List.nil()).reverse());
      }
    }

    public final  List> traverseList(F> f){
        return isSuccess() ?
            f.f(success()).map(Validation::success) :
            List.iterableList(fail(e.left().value()));
    }

    public final  Stream> traverseStream(F> f){
        return isSuccess() ?
            f.f(success()).map(Validation::success) :
            Stream.iterableStream(fail(e.left().value()));
    }

    public final  Option> traverseOption(F> f){
        return isSuccess() ?
            f.f(success()).map(Validation::success) :
            Option.some(fail(e.left().value()));
    }

    public final  IO> traverseIO(F> f){
        return isSuccess() ?
            IOFunctions.map(f.f(success()), Validation::success) :
            IOFunctions.unit(fail(e.left().value()));
    }

    public final  P1> traverseP1(F> f){
        return isSuccess() ?
                f.f(success()).map(Validation::success) :
                p(fail(e.left().value()));
    }


    public static  List fails(List> list) {
        return list.filter(Validation::isFail).map(v -> v.fail());
    }

    public static  List successes(List> list) {
        return list.filter(Validation::isSuccess).map(v -> v.success());
    }

  /**
   * A failing projection of a validation.
   */
  public static final class FailProjection implements Iterable {
    private final Validation v;

    private FailProjection(final Validation v) {
      this.v = v;
    }

    /**
     * Returns the underlying validation.
     *
     * @return The underlying validation.
     */
    public Validation 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 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) {
      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 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 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 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  Validation map(final F 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  Validation bind(final F> 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  Validation sequence(final Validation v) {
      return bind(e1 -> v);
    }


	  /**
     * Returns None if this is a success or if the given predicate p does not hold for the
     * failing value, otherwise, returns a fail in Some.
     *
     * @param f The predicate function to test on this failing value.
     * @return None if this is a success or if the given predicate p does not hold for the
     *         failing value, otherwise, returns a fail in Some.
     */
    public  Option> filter(final F f) {
      return v.toEither().left().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  Validation apply(final Validation, T> v) {
      return v.f().bind(this::map);
    }

    /**
     * Returns true 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 true 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 f) {
      return v.toEither().left().forall(f);
    }

    /**
     * Returns false 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 false 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 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 toList() {
      return v.toEither().left().toList();
    }

    /**
     * Returns the failing value in Some if there is one, otherwise None.
     *
     * @return The failing value in Some if there is one, otherwise None.
     */
    public Option 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 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 toStream() {
      return v.toEither().left().toStream();
    }

    /**
     * Returns an iterator for this projection. This method exists to permit the use in a for-each loop.
     *
     * @return A iterator for this projection.
     */
    public Iterator 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, 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  Validation validation(final Either 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  F, Validation> 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  F, Either> 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  Validation 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  Validation 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  Validation, T> failNEL(final E e) {
    return fail(NonEmptyList.nel(e));
  }

  /**
   * Returns a validation based on a boolean condition. If the condition is true, 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 false.
   * @param t The succeeding value to use if the condition is true.
   * @return A validation based on a boolean condition.
   */
  public static  Validation 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 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> 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 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> 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 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> 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 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> 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 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> 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 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> parseShort = Validation::parseShort;

  /**
   * Partitions the list into the list of fails and the list of successes
   */
  public static  P2, List> partition(List> 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.anyShow(), Show.anyShow()).showS(this);
    }




}