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

fj.test.Arbitrary Maven / Gradle / Ivy

package fj.test;

import fj.F;
import fj.F2;
import fj.F3;
import fj.F4;
import fj.F5;
import fj.F6;
import fj.F7;
import fj.F8;
import fj.Function;
import fj.Bottom;

import static fj.Function.compose;
import static fj.P.p;
import fj.P1;
import fj.P2;
import fj.P3;
import fj.P4;
import fj.P5;
import fj.P6;
import fj.P7;
import fj.P8;
import fj.data.*;
import fj.LcgRng;
import fj.Ord;

import static fj.data.Either.left;
import static fj.data.Either.right;
import static fj.data.Enumerator.charEnumerator;
import static fj.data.List.asString;
import static fj.data.List.list;
import static fj.data.Option.some;

import fj.function.Effect1;

import static fj.data.Stream.range;
import static fj.test.Gen.choose;
import static fj.test.Gen.elements;
import static fj.test.Gen.fail;
import static fj.test.Gen.frequency;
import static fj.test.Gen.listOf;
import static fj.test.Gen.oneOf;
import static fj.test.Gen.promote;
import static fj.test.Gen.sized;
import static fj.test.Gen.value;

import static java.lang.Math.abs;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Calendar;
import java.util.Date;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Locale;
import static java.util.Locale.getAvailableLocales;
import java.util.PriorityQueue;
import java.util.Properties;
import java.util.Stack;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Vector;
import java.util.WeakHashMap;
import static java.util.EnumSet.copyOf;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;

/**
 * The type used to generate arbitrary values of the given type parameter (A). Common
 * arbitrary implementations are provided.
 *
 * @version %build.number%
 */
public final class Arbitrary {
  /**
   * The generator associated with this arbitrary.
   */
  @SuppressWarnings({"PublicField"})
  public final Gen gen;

  private Arbitrary(final Gen gen) {
    this.gen = gen;
  }

  /**
   * Constructs and arbitrary with the given generator.
   *
   * @param g The generator to construct an arbitrary with.
   * @return A new arbitrary that uses the given generator.
   */
  public static  Arbitrary arbitrary(final Gen g) {
    return new Arbitrary(g);
  }

  /**
   * An arbitrary for functions.
   *
   * @param c The coarbitrary for the function domain.
   * @param a The arbitrary for the function codomain.
   * @return An arbitrary for functions.
   */
  public static  Arbitrary> arbF(final Coarbitrary c, final Arbitrary a) {
    return arbitrary(promote(new F>() {
      public Gen f(final A x) {
        return c.coarbitrary(x, a.gen);
      }
    }));
  }

    public static  Arbitrary> arbReader(Coarbitrary aa, Arbitrary ab) {
        return arbitrary(Arbitrary.arbF(aa, ab).gen.map(f -> Reader.unit(f)));
    }

    /**
     * An arbitrary for state.
     */
    public static  Arbitrary> arbState(Arbitrary as, Coarbitrary cs, Arbitrary aa) {
        return arbitrary(arbF(cs, arbP2(as, aa)).gen.map(f -> State.unit(f)));
    }

    /**
     * An arbitrary for the LcgRng.
     */
    public static  Arbitrary arbLcgRng() {
        return arbitrary(Arbitrary.arbLong.gen.map(l -> new LcgRng(l)));
    }

  /**
   * An arbitrary for functions.
   *
   * @param a The arbitrary for the function codomain.
   * @return An arbitrary for functions.
   */
  public static  Arbitrary> arbFInvariant(final Arbitrary a) {
    return arbitrary(a.gen.map(Function.constant()));
  }

  /**
   * An arbitrary for function-2.
   *
   * @param ca A coarbitrary for the part of the domain of the function.
   * @param cb A coarbitrary for the part of the domain of the function.
   * @param a  An arbitrary for the codomain of the function.
   * @return An arbitrary for function-2.
   */
  public static  Arbitrary> arbF2(final Coarbitrary ca, final Coarbitrary cb,
                                                       final Arbitrary a) {
    return arbitrary(arbF(ca, arbF(cb, a)).gen.map(Function.uncurryF2()));
  }

  /**
   * An arbitrary for function-2.
   *
   * @param a The arbitrary for the function codomain.
   * @return An arbitrary for function-2.
   */
  public static  Arbitrary> arbF2Invariant(final Arbitrary a) {
    return arbitrary(a.gen.map(
        compose(Function.uncurryF2(), compose(Function.>constant(), Function.constant()))));
  }

  /**
   * An arbitrary for function-3.
   *
   * @param ca A coarbitrary for the part of the domain of the function.
   * @param cb A coarbitrary for the part of the domain of the function.
   * @param cc A coarbitrary for the part of the domain of the function.
   * @param a  An arbitrary for the codomain of the function.
   * @return An arbitrary for function-3.
   */
  public static  Arbitrary> arbF3(final Coarbitrary ca, final Coarbitrary cb,
                                                             final Coarbitrary cc, final Arbitrary a) {
    return arbitrary(arbF(ca, arbF(cb, arbF(cc, a))).gen.map(Function.uncurryF3()));
  }

  /**
   * An arbitrary for function-3.
   *
   * @param a The arbitrary for the function codomain.
   * @return An arbitrary for function-3.
   */
  public static  Arbitrary> arbF3Invariant(final Arbitrary a) {
    return arbitrary(a.gen.map(compose(Function.uncurryF3(), compose(Function.>>constant(),
                                                                                 compose(
                                                                                     Function.>constant(),
                                                                                     Function.constant())))));
  }

  /**
   * An arbitrary for function-4.
   *
   * @param ca A coarbitrary for the part of the domain of the function.
   * @param cb A coarbitrary for the part of the domain of the function.
   * @param cc A coarbitrary for the part of the domain of the function.
   * @param cd A coarbitrary for the part of the domain of the function.
   * @param a  An arbitrary for the codomain of the function.
   * @return An arbitrary for function-4.
   */
  public static  Arbitrary> arbF4(final Coarbitrary ca, final Coarbitrary cb,
                                                                   final Coarbitrary cc, final Coarbitrary cd,
                                                                   final Arbitrary a) {
    return arbitrary(arbF(ca, arbF(cb, arbF(cc, arbF(cd, a)))).gen.map(Function.uncurryF4()));
  }

  /**
   * An arbitrary for function-4.
   *
   * @param a The arbitrary for the function codomain.
   * @return An arbitrary for function-4.
   */
  public static  Arbitrary> arbF4Invariant(final Arbitrary a) {
    return arbitrary(a.gen.map(compose(Function.uncurryF4(),
                                       compose(Function.>>>constant(),
                                               compose(Function.>>constant(),
                                                       compose(Function.>constant(),
                                                               Function.constant()))))));
  }

  /**
   * An arbitrary for function-5.
   *
   * @param ca A coarbitrary for the part of the domain of the function.
   * @param cb A coarbitrary for the part of the domain of the function.
   * @param cc A coarbitrary for the part of the domain of the function.
   * @param cd A coarbitrary for the part of the domain of the function.
   * @param ce A coarbitrary for the part of the domain of the function.
   * @param a  An arbitrary for the codomain of the function.
   * @return An arbitrary for function-5.
   */
  public static  Arbitrary> arbF5(final Coarbitrary ca,
                                                                           final Coarbitrary cb,
                                                                           final Coarbitrary cc,
                                                                           final Coarbitrary cd,
                                                                           final Coarbitrary ce,
                                                                           final Arbitrary a) {
    return arbitrary(
        arbF(ca, arbF(cb, arbF(cc, arbF(cd, arbF(ce, a))))).gen.map(Function.uncurryF5()));
  }

  /**
   * An arbitrary for function-5.
   *
   * @param a The arbitrary for the function codomain.
   * @return An arbitrary for function-5.
   */
  public static  Arbitrary> arbF5Invariant(final Arbitrary a) {
    return arbitrary(a.gen.map(compose(Function.uncurryF5(),
                                       compose(Function.>>>>constant(),
                                               compose(Function.>>>constant(),
                                                       compose(Function.>>constant(),
                                                               compose(Function.>constant(),
                                                                       Function.constant())))))));
  }

  /**
   * An arbitrary for function-6.
   *
   * @param ca A coarbitrary for the part of the domain of the function.
   * @param cb A coarbitrary for the part of the domain of the function.
   * @param cc A coarbitrary for the part of the domain of the function.
   * @param cd A coarbitrary for the part of the domain of the function.
   * @param ce A coarbitrary for the part of the domain of the function.
   * @param cf A coarbitrary for the part of the domain of the function.
   * @param a  An arbitrary for the codomain of the function.
   * @return An arbitrary for function-6.
   */
  public static  Arbitrary> arbF6(final Coarbitrary ca,
                                                                                 final Coarbitrary cb,
                                                                                 final Coarbitrary cc,
                                                                                 final Coarbitrary cd,
                                                                                 final Coarbitrary ce,
                                                                                 final Coarbitrary cf,
                                                                                 final Arbitrary a) {
    return arbitrary(arbF(ca, arbF(cb, arbF(cc, arbF(cd, arbF(ce, arbF(cf, a)))))).gen.map(
        Function.uncurryF6()));
  }

  /**
   * An arbitrary for function-6.
   *
   * @param a The arbitrary for the function codomain.
   * @return An arbitrary for function-6.
   */
  public static  Arbitrary> arbF6Invariant(final Arbitrary a) {
    return arbitrary(a.gen.map(compose(Function.uncurryF6(),
                                       compose(Function.>>>>>constant(),
                                               compose(Function.>>>>constant(),
                                                       compose(Function.>>>constant(),
                                                               compose(Function.>>constant(),
                                                                       compose(Function.>constant(),
                                                                               Function.constant()))))))));
  }

  /**
   * An arbitrary for function-7.
   *
   * @param ca A coarbitrary for the part of the domain of the function.
   * @param cb A coarbitrary for the part of the domain of the function.
   * @param cc A coarbitrary for the part of the domain of the function.
   * @param cd A coarbitrary for the part of the domain of the function.
   * @param ce A coarbitrary for the part of the domain of the function.
   * @param cf A coarbitrary for the part of the domain of the function.
   * @param cg A coarbitrary for the part of the domain of the function.
   * @param a  An arbitrary for the codomain of the function.
   * @return An arbitrary for function-7.
   */
  public static  Arbitrary> arbF7(final Coarbitrary ca,
                                                                                       final Coarbitrary cb,
                                                                                       final Coarbitrary cc,
                                                                                       final Coarbitrary cd,
                                                                                       final Coarbitrary ce,
                                                                                       final Coarbitrary cf,
                                                                                       final Coarbitrary cg,
                                                                                       final Arbitrary a) {
    return arbitrary(arbF(ca, arbF(cb, arbF(cc, arbF(cd, arbF(ce, arbF(cf, arbF(cg, a))))))).gen.map(
        Function.uncurryF7()));
  }

  /**
   * An arbitrary for function-7.
   *
   * @param a The arbitrary for the function codomain.
   * @return An arbitrary for function-7.
   */
  public static  Arbitrary> arbF7Invariant(final Arbitrary a) {
    return arbitrary(a.gen.map(compose(Function.uncurryF7(),
                                       compose(Function.>>>>>>constant(),
                                               compose(Function.>>>>>constant(),
                                                       compose(Function.>>>>constant(),
                                                               compose(Function.>>>constant(),
                                                                       compose(Function.>>constant(),
                                                                               compose(Function.>constant(),
                                                                                       Function.constant())))))))));
  }

  /**
   * An arbitrary for function-8.
   *
   * @param ca A coarbitrary for the part of the domain of the function.
   * @param cb A coarbitrary for the part of the domain of the function.
   * @param cc A coarbitrary for the part of the domain of the function.
   * @param cd A coarbitrary for the part of the domain of the function.
   * @param ce A coarbitrary for the part of the domain of the function.
   * @param cf A coarbitrary for the part of the domain of the function.
   * @param cg A coarbitrary for the part of the domain of the function.
   * @param ch A coarbitrary for the part of the domain of the function.
   * @param a  An arbitrary for the codomain of the function.
   * @return An arbitrary for function-8.
   */
  public static  Arbitrary> arbF8(final Coarbitrary ca,
                                                                                             final Coarbitrary cb,
                                                                                             final Coarbitrary cc,
                                                                                             final Coarbitrary cd,
                                                                                             final Coarbitrary ce,
                                                                                             final Coarbitrary cf,
                                                                                             final Coarbitrary cg,
                                                                                             final Coarbitrary ch,
                                                                                             final Arbitrary a) {
    return arbitrary(arbF(ca, arbF(cb, arbF(cc, arbF(cd, arbF(ce, arbF(cf, arbF(cg, arbF(ch, a)))))))).gen.map(
        Function.uncurryF8()));
  }

  /**
   * An arbitrary for function-8.
   *
   * @param a The arbitrary for the function codomain.
   * @return An arbitrary for function-8.
   */
  public static  Arbitrary> arbF8Invariant(
      final Arbitrary a) {
    return arbitrary(a.gen.map(compose(Function.uncurryF8(),
                                       compose(Function.>>>>>>>constant(),
                                               compose(Function.>>>>>>constant(),
                                                       compose(Function.>>>>>constant(),
                                                               compose(
                                                                   Function.>>>>constant(),
                                                                   compose(Function.>>>constant(),
                                                                           compose(
                                                                               Function.>>constant(),
                                                                               compose(Function.>constant(),
                                                                                       Function.constant()))))))))));
  }

  /**
   * An arbitrary implementation for boolean values.
   */
  public static final Arbitrary arbBoolean = arbitrary(elements(true, false));

  /**
   * An arbitrary implementation for integer values.
   */
  public static final Arbitrary arbInteger = arbitrary(sized(new F>() {
    public Gen f(final Integer i) {
      return choose(-i, i);
    }
  }));

  /**
   * An arbitrary implementation for integer values that checks boundary values (0, 1, -1,
   * max, min, max - 1, min + 1) with a frequency of 1% each then generates from {@link
   * #arbInteger} the remainder of the time (93%).
   */
  public static final Arbitrary arbIntegerBoundaries = arbitrary(sized(new F>() {
    @SuppressWarnings("unchecked")
    public Gen f(final Integer i) {
      return frequency(list(p(1, value(0)),
                            p(1, value(1)),
                            p(1, value(-1)),
                            p(1, value(Integer.MAX_VALUE)),
                            p(1, value(Integer.MIN_VALUE)),
                            p(1, value(Integer.MAX_VALUE - 1)),
                            p(1, value(Integer.MIN_VALUE + 1)),
                            p(93, arbInteger.gen)));
    }
  }));

  /**
   * An arbitrary implementation for long values.
   */
  public static final Arbitrary arbLong =
      arbitrary(arbInteger.gen.bind(arbInteger.gen, new F>() {
        public F f(final Integer i1) {
          return new F() {
            public Long f(final Integer i2) {
              return (long) i1 << 32L & i2;
            }
          };
        }
      }));

  /**
   * An arbitrary implementation for long values that checks boundary values (0, 1, -1, max,
   * min, max - 1, min + 1) with a frequency of 1% each then generates from {@link #arbLong}
   * the remainder of the time (93%).
   */
  public static final Arbitrary arbLongBoundaries = arbitrary(sized(new F>() {
    @SuppressWarnings("unchecked")
    public Gen f(final Integer i) {
      return frequency(list(p(1, value(0L)),
                            p(1, value(1L)),
                            p(1, value(-1L)),
                            p(1, value(Long.MAX_VALUE)),
                            p(1, value(Long.MIN_VALUE)),
                            p(1, value(Long.MAX_VALUE - 1L)),
                            p(1, value(Long.MIN_VALUE + 1L)),
                            p(93, arbLong.gen)));
    }
  }));

  /**
   * An arbitrary implementation for byte values.
   */
  public static final Arbitrary arbByte = arbitrary(arbInteger.gen.map(new F() {
    public Byte f(final Integer i) {
      return (byte) i.intValue();
    }
  }));

  /**
   * An arbitrary implementation for byte values that checks boundary values (0, 1, -1, max,
   * min, max - 1, min + 1) with a frequency of 1% each then generates from {@link #arbByte}
   * the remainder of the time (93%).
   */
  public static final Arbitrary arbByteBoundaries = arbitrary(sized(new F>() {
    @SuppressWarnings("unchecked")
    public Gen f(final Integer i) {
      return frequency(list(p(1, value((byte) 0)),
                            p(1, value((byte) 1)),
                            p(1, value((byte) -1)),
                            p(1, value(Byte.MAX_VALUE)),
                            p(1, value(Byte.MIN_VALUE)),
                            p(1, value((byte) (Byte.MAX_VALUE - 1))),
                            p(1, value((byte) (Byte.MIN_VALUE + 1))),
                            p(93, arbByte.gen)));
    }
  }));

  /**
   * An arbitrary implementation for short values.
   */
  public static final Arbitrary arbShort = arbitrary(arbInteger.gen.map(new F() {
    public Short f(final Integer i) {
      return (short) i.intValue();
    }
  }));

  /**
   * An arbitrary implementation for short values that checks boundary values (0, 1, -1, max,
   * min, max - 1, min + 1) with a frequency of 1% each then generates from {@link #arbShort}
   * the remainder of the time (93%).
   */
  public static final Arbitrary arbShortBoundaries = arbitrary(sized(new F>() {
    @SuppressWarnings("unchecked")
    public Gen f(final Integer i) {
      return frequency(list(p(1, value((short) 0)),
                            p(1, value((short) 1)),
                            p(1, value((short) -1)),
                            p(1, value(Short.MAX_VALUE)),
                            p(1, value(Short.MIN_VALUE)),
                            p(1, value((short) (Short.MAX_VALUE - 1))),
                            p(1, value((short) (Short.MIN_VALUE + 1))),
                            p(93, arbShort.gen)));
    }
  }));

  /**
   * An arbitrary implementation for character values.
   */
  public static final Arbitrary arbCharacter = arbitrary(choose(0, 65536).map(new F() {
    public Character f(final Integer i) {
      return (char) i.intValue();
    }
  }));

  /**
   * An arbitrary implementation for character values that checks boundary values (max, min,
   * max - 1, min + 1) with a frequency of 1% each then generates from {@link #arbCharacter}
   * the remainder of the time (96%).
   */
  public static final Arbitrary arbCharacterBoundaries = arbitrary(sized(new F>() {
    @SuppressWarnings("unchecked")
    public Gen f(final Integer i) {
      return frequency(list(p(1, value(Character.MIN_VALUE)),
                            p(1, value((char) (Character.MIN_VALUE + 1))),
                            p(1, value(Character.MAX_VALUE)),
                            p(1, value((char) (Character.MAX_VALUE - 1))),
                            p(95, arbCharacter.gen)));
    }
  }));

  /**
   * An arbitrary implementation for double values.
   */
  public static final Arbitrary arbDouble = arbitrary(sized(new F>() {
    public Gen f(final Integer i) {
      return choose((double) -i, i);
    }
  }));

  /**
   * An arbitrary implementation for double values that checks boundary values (0, 1, -1, max,
   * min, min (normal), NaN, -infinity, infinity, max - 1) with a frequency of 1% each then
   * generates from {@link #arbDouble} the remainder of the time (91%).
   */
  public static final Arbitrary arbDoubleBoundaries = arbitrary(sized(new F>() {
    @SuppressWarnings("unchecked")
    public Gen f(final Integer i) {
      return frequency(list(p(1, value(0D)),
                            p(1, value(1D)),
                            p(1, value(-1D)),
                            p(1, value(Double.MAX_VALUE)),
                            p(1, value(Double.MIN_VALUE)),
                            p(1, value(Double.NaN)),
                            p(1, value(Double.NEGATIVE_INFINITY)),
                            p(1, value(Double.POSITIVE_INFINITY)),
                            p(1, value(Double.MAX_VALUE - 1D)),
                            p(91, arbDouble.gen)));
    }
  }));

  /**
   * An arbitrary implementation for float values.
   */
  public static final Arbitrary arbFloat = arbitrary(arbDouble.gen.map(new F() {
    public Float f(final Double d) {
      return (float) d.doubleValue();
    }
  }));

  /**
   * An arbitrary implementation for float values that checks boundary values (0, 1, -1, max,
   * min, NaN, -infinity, infinity, max - 1) with a frequency of 1% each then generates from
   * {@link #arbFloat} the remainder of the time (91%).
   */
  public static final Arbitrary arbFloatBoundaries = arbitrary(sized(new F>() {
    @SuppressWarnings("unchecked")
    public Gen f(final Integer i) {
      return frequency(list(p(1, value(0F)),
                            p(1, value(1F)),
                            p(1, value(-1F)),
                            p(1, value(Float.MAX_VALUE)),
                            p(1, value(Float.MIN_VALUE)),
                            p(1, value(Float.NaN)),
                            p(1, value(Float.NEGATIVE_INFINITY)),
                            p(1, value(Float.POSITIVE_INFINITY)),
                            p(1, value(Float.MAX_VALUE - 1F)),
                            p(91, arbFloat.gen)));
    }
  }));

  /**
   * An arbitrary implementation for string values.
   */
  public static final Arbitrary arbString =
      arbitrary(arbList(arbCharacter).gen.map(new F, String>() {
        public String f(final List cs) {
          return asString(cs);
        }
      }));

  /**
   * An arbitrary implementation for string values with characters in the US-ASCII range.
   */
  public static final Arbitrary arbUSASCIIString =
      arbitrary(arbList(arbCharacter).gen.map(new F, String>() {
        public String f(final List cs) {
          return asString(cs.map(new F() {
            public Character f(final Character c) {
              return (char) (c % 128);
            }
          }));
        }
      }));

  /**
   * An arbitrary implementation for string values with alpha-numeric characters.
   */
  public static final Arbitrary arbAlphaNumString =
      arbitrary(arbList(arbitrary(elements(range(charEnumerator, 'a', 'z').append(
          range(charEnumerator, 'A', 'Z')).append(
          range(charEnumerator, '0', '9')).toArray().array(Character[].class)))).gen.map(asString()));

  /**
   * An arbitrary implementation for string buffer values.
   */
  public static final Arbitrary arbStringBuffer =
      arbitrary(arbString.gen.map(new F() {
        public StringBuffer f(final String s) {
          return new StringBuffer(s);
        }
      }));

  /**
   * An arbitrary implementation for string builder values.
   */
  public static final Arbitrary arbStringBuilder =
      arbitrary(arbString.gen.map(new F() {
        public StringBuilder f(final String s) {
          return new StringBuilder(s);
        }
      }));

  /**
   * Returns an arbitrary implementation for generators.
   *
   * @param aa an arbitrary implementation for the type over which the generator is defined.
   * @return An arbitrary implementation for generators.
   */
  public static  Arbitrary> arbGen(final Arbitrary aa) {
    return arbitrary(sized(new F>>() {
      @SuppressWarnings({"IfMayBeConditional"})
      public Gen> f(final Integer i) {
        if (i == 0)
          return fail();
        else
          return aa.gen.map(new F>() {
            public Gen f(final A a) {
              return value(a);
            }
          }).resize(i - 1);
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for optional values.
   *
   * @param aa an arbitrary implementation for the type over which the optional value is defined.
   * @return An arbitrary implementation for optional values.
   */
  public static  Arbitrary> arbOption(final Arbitrary aa) {
    return arbitrary(sized(new F>>() {
      public Gen> f(final Integer i) {
        return i == 0 ?
               value(Option.none()) :
               aa.gen.map(new F>() {
                 public Option f(final A a) {
                   return some(a);
                 }
               }).resize(i - 1);
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for the disjoint union.
   *
   * @param aa An arbitrary implementation for the type over which one side of the disjoint union is
   *           defined.
   * @param ab An arbitrary implementation for the type over which one side of the disjoint union is
   *           defined.
   * @return An arbitrary implementation for the disjoint union.
   */
  @SuppressWarnings({"unchecked"})
  public static  Arbitrary> arbEither(final Arbitrary aa, final Arbitrary ab) {
    final Gen> left = aa.gen.map(new F>() {
      public Either f(final A a) {
        return left(a);
      }
    });
    final Gen> right = ab.gen.map(new F>() {
      public Either f(final B b) {
        return right(b);
      }
    });
    return arbitrary(oneOf(list(left, right)));
  }

  /**
   * Returns an arbitrary implementation for lists.
   *
   * @param aa An arbitrary implementation for the type over which the list is defined.
   * @return An arbitrary implementation for lists.
   */
  public static  Arbitrary> arbList(final Arbitrary aa) {
    return arbitrary(listOf(aa.gen));
  }

	/**
	 * Returns an arbitrary list of integers.
	 */
	public static  Arbitrary> arbListInteger() {
		return arbitrary(listOf(arbInteger.gen));
	}

	/**
	 * Returns an arbitrary list of strings.
	 */
	public static  Arbitrary> arbListString() {
		return arbitrary(listOf(arbString.gen));
	}

	/**
	 * Returns an arbitrary list of booleans.
	 */
	public static  Arbitrary> arbListBoolean() {
		return arbitrary(listOf(arbBoolean.gen));
	}

	/**
	 * Returns an arbitrary list of doubles.
	 */
	public static  Arbitrary> arbListDouble() {
		return arbitrary(listOf(arbDouble.gen));
	}

	public static  Arbitrary> arbNonEmptyList(final Arbitrary aa) {
    return arbitrary(Gen.listOf1(aa.gen).map(list -> NonEmptyList.fromList(list).some()));
  }

    /**
     * Returns an arbitrary Validation for the given arbitrary parameters.
     */
    public static  Arbitrary> arbValidation(final Arbitrary aa, final Arbitrary ab) {
        return arbitrary(arbBoolean.gen.bind(bool -> bool ? ab.gen.map(b -> Validation.success(b)) : aa.gen.map(a -> Validation.fail(a))));
    }

  /**
   * Returns an arbitrary implementation for streams.
   *
   * @param aa An arbitrary implementation for the type over which the stream is defined.
   * @return An arbitrary implementation for streams.
   */
  public static  Arbitrary> arbStream(final Arbitrary aa) {
    return arbitrary(arbList(aa).gen.map(new F, Stream>() {
      public Stream f(final List as) {
        return as.toStream();
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for arrays.
   *
   * @param aa An arbitrary implementation for the type over which the array is defined.
   * @return An arbitrary implementation for arrays.
   */
  public static  Arbitrary> arbArray(final Arbitrary aa) {
    return arbitrary(arbList(aa).gen.map(new F, Array>() {
      public Array f(final List as) {
        return as.toArray();
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for sequences.
   *
   * @param aa An arbitrary implementation for the type over which the sequence is defined.
   * @return An arbitrary implementation for sequences.
   */
  @SuppressWarnings("unchecked")
  public static  Arbitrary> arbSeq(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(array -> Seq.seq((A[]) array.array())));
  }

	public static  Arbitrary> arbSet(Ord ord, final Arbitrary aa) {
		return arbitrary(arbList(aa).gen.map(list -> Set.iterableSet(ord, list)));
	}

    public static  Arbitrary> arbSet(Ord ord, final Arbitrary aa, int max) {
        Gen> g = Gen.choose(0, max).bind(i -> Gen.sequenceN(i, aa.gen)).map(list -> Set.iterableSet(ord, list));
        return arbitrary(g);
    }


    /**
   * Returns an arbitrary implementation for throwables.
   *
   * @param as An arbitrary used for the throwable message.
   * @return An arbitrary implementation for throwables.
   */
  public static Arbitrary arbThrowable(final Arbitrary as) {
    return arbitrary(as.gen.map(new F() {
      public Throwable f(final String msg) {
        return new Throwable(msg);
      }
    }));
  }

  /**
   * An arbitrary implementation for throwables.
   */
  public static final Arbitrary arbThrowable = arbThrowable(arbString);

  // BEGIN java.util

  /**
   * Returns an arbitrary implementation for array lists.
   *
   * @param aa An arbitrary implementation for the type over which the array list is defined.
   * @return An arbitrary implementation for array lists.
   */
  public static  Arbitrary> arbArrayList(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, ArrayList>() {
      public ArrayList f(final Array a) {
        return new ArrayList(a.toCollection());
      }
    }));
  }

  /**
   * An arbitrary implementation for bit sets.
   */
  public static final Arbitrary arbBitSet =
      arbitrary(arbList(arbBoolean).gen.map(new F, BitSet>() {
        public BitSet f(final List bs) {
          final BitSet s = new BitSet(bs.length());
          bs.zipIndex().foreachDoEffect(new Effect1>() {
              public void f(final P2 bi) {
                  s.set(bi._2(), bi._1());
              }
          });
          return s;
        }
      }));

  /**
   * An arbitrary implementation for calendars.
   */
  public static final Arbitrary arbCalendar = arbitrary(arbLong.gen.map(new F() {
    public Calendar f(final Long i) {
      final Calendar c = Calendar.getInstance();
      c.setTimeInMillis(i);
      return c;
    }
  }));

  /**
   * An arbitrary implementation for dates.
   */
  public static final Arbitrary arbDate = arbitrary(arbLong.gen.map(new F() {
    public Date f(final Long i) {
      return new Date(i);
    }
  }));

  /**
   * Returns an arbitrary implementation for a Java enumeration.
   *
   * @param clazz The type of enum to return an arbtrary of.
   * @return An arbitrary for instances of the supplied enum type.
   */
  public static > Arbitrary arbEnumValue(final Class clazz) {
    return arbitrary(Gen.elements(clazz.getEnumConstants()));
  }

  /**
   * Returns an arbitrary implementation for enum maps.
   *
   * @param ak An arbitrary implementation for the type over which the enum map's keys are defined.
   * @param av An arbitrary implementation for the type over which the enum map's values are
   *           defined.
   * @return An arbitrary implementation for enum maps.
   */
  public static , V> Arbitrary> arbEnumMap(final Arbitrary ak,
                                                                           final Arbitrary av) {
    return arbitrary(arbHashtable(ak, av).gen.map(new F, EnumMap>() {
      @SuppressWarnings({"UseOfObsoleteCollectionType"})
      public EnumMap f(final Hashtable ht) {
        return new EnumMap(ht);
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for enum sets.
   *
   * @param aa An arbitrary implementation for the type over which the enum set is defined.
   * @return An arbitrary implementation for enum sets.
   */
  public static > Arbitrary> arbEnumSet(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, EnumSet>() {
      public EnumSet f(final Array a) {
        return copyOf(a.toCollection());
      }
    }));
  }

  /**
   * An arbitrary implementation for gregorian calendars.
   */
  public static final Arbitrary arbGregorianCalendar =
      arbitrary(arbLong.gen.map(new F() {
        public GregorianCalendar f(final Long i) {
          final GregorianCalendar c = new GregorianCalendar();
          c.setTimeInMillis(i);
          return c;
        }
      }));

  /**
   * Returns an arbitrary implementation for hash maps.
   *
   * @param ak An arbitrary implementation for the type over which the hash map's keys are defined.
   * @param av An arbitrary implementation for the type over which the hash map's values are
   *           defined.
   * @return An arbitrary implementation for hash maps.
   */
  public static  Arbitrary> arbHashMap(final Arbitrary ak, final Arbitrary av) {
    return arbitrary(arbHashtable(ak, av).gen.map(new F, HashMap>() {
      @SuppressWarnings({"UseOfObsoleteCollectionType"})
      public HashMap f(final Hashtable ht) {
        return new HashMap(ht);
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for hash sets.
   *
   * @param aa An arbitrary implementation for the type over which the hash set is defined.
   * @return An arbitrary implementation for hash sets.
   */
  public static  Arbitrary> arbHashSet(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, HashSet>() {
      public HashSet f(final Array a) {
        return new HashSet(a.toCollection());
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for hash tables.
   *
   * @param ak An arbitrary implementation for the type over which the hash table's keys are
   *           defined.
   * @param av An arbitrary implementation for the type over which the hash table's values are
   *           defined.
   * @return An arbitrary implementation for hash tables.
   */
  public static  Arbitrary> arbHashtable(final Arbitrary ak, final Arbitrary av) {
    return arbitrary(arbList(ak).gen.bind(arbList(av).gen, new F, F, Hashtable>>() {
      public F, Hashtable> f(final List ks) {
        return new F, Hashtable>() {
          @SuppressWarnings({"UseOfObsoleteCollectionType"})
          public Hashtable f(final List vs) {
            final Hashtable t = new Hashtable();

            ks.zip(vs).foreachDoEffect(new Effect1>() {
                public void f(final P2 kv) {
                    t.put(kv._1(), kv._2());
                }
            });

            return t;
          }
        };
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for identity hash maps.
   *
   * @param ak An arbitrary implementation for the type over which the identity hash map's keys are
   *           defined.
   * @param av An arbitrary implementation for the type over which the identity hash map's values
   *           are defined.
   * @return An arbitrary implementation for identity hash maps.
   */
  public static  Arbitrary> arbIdentityHashMap(final Arbitrary ak,
                                                                           final Arbitrary av) {
    return arbitrary(arbHashtable(ak, av).gen.map(new F, IdentityHashMap>() {
      @SuppressWarnings({"UseOfObsoleteCollectionType"})
      public IdentityHashMap f(final Hashtable ht) {
        return new IdentityHashMap(ht);
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for linked hash maps.
   *
   * @param ak An arbitrary implementation for the type over which the linked hash map's keys are
   *           defined.
   * @param av An arbitrary implementation for the type over which the linked hash map's values are
   *           defined.
   * @return An arbitrary implementation for linked hash maps.
   */
  public static  Arbitrary> arbLinkedHashMap(final Arbitrary ak, final Arbitrary av) {
    return arbitrary(arbHashtable(ak, av).gen.map(new F, LinkedHashMap>() {
      @SuppressWarnings({"UseOfObsoleteCollectionType"})
      public LinkedHashMap f(final Hashtable ht) {
        return new LinkedHashMap(ht);
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for hash sets.
   *
   * @param aa An arbitrary implementation for the type over which the hash set is defined.
   * @return An arbitrary implementation for hash sets.
   */
  public static  Arbitrary> arbLinkedHashSet(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, LinkedHashSet>() {
      public LinkedHashSet f(final Array a) {
        return new LinkedHashSet(a.toCollection());
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for linked lists.
   *
   * @param aa An arbitrary implementation for the type over which the linked list is defined.
   * @return An arbitrary implementation for linked lists.
   */
  public static  Arbitrary> arbLinkedList(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, LinkedList>() {
      public LinkedList f(final Array a) {
        return new LinkedList(a.toCollection());
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for priority queues.
   *
   * @param aa An arbitrary implementation for the type over which the priority queue is defined.
   * @return An arbitrary implementation for priority queues.
   */
  public static  Arbitrary> arbPriorityQueue(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, PriorityQueue>() {
      public PriorityQueue f(final Array a) {
        return new PriorityQueue(a.toCollection());
      }
    }));
  }

  /**
   * An arbitrary implementation for properties.
   */
  public static final Arbitrary arbProperties =
      arbitrary(arbHashtable(arbString, arbString).gen.map(new F, Properties>() {
        @SuppressWarnings({"UseOfObsoleteCollectionType"})
        public Properties f(final Hashtable ht) {
          final Properties p = new Properties();

          for (final String k : ht.keySet()) {
            p.setProperty(k, ht.get(k));
          }

          return p;
        }
      }));

  /**
   * Returns an arbitrary implementation for stacks.
   *
   * @param aa An arbitrary implementation for the type over which the stack is defined.
   * @return An arbitrary implementation for stacks.
   */
  public static  Arbitrary> arbStack(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, Stack>() {
      public Stack f(final Array a) {
        final Stack s = new Stack();
        s.addAll(a.toCollection());
        return s;
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for java.util tree maps.
   *
   * @param ak An arbitrary implementation for the type over which the tree map's keys are defined.
   * @param av An arbitrary implementation for the type over which the tree map's values are
   *           defined.
   * @return An arbitrary implementation for tree maps.
   */
  public static  Arbitrary> arbJavaTreeMap(final Arbitrary ak, final Arbitrary av) {
    return arbitrary(arbHashtable(ak, av).gen.map(new F, java.util.TreeMap>() {
      @SuppressWarnings({"UseOfObsoleteCollectionType"})
      public java.util.TreeMap f(final Hashtable ht) {
        return new java.util.TreeMap(ht);
      }
    }));
  }

    /**
     * Returns an arbitrary implementation for tree maps.
     */
    public static  Arbitrary> arbTreeMap(Ord ord, Arbitrary>> al) {
        return arbitrary(al.gen.map(list -> fj.data.TreeMap.iterableTreeMap(ord, list)));
    }

    /**
     * Returns an arbitrary implementation for tree maps.
     */
    public static  Arbitrary> arbTreeMap(Ord ord, Arbitrary ak, Arbitrary av) {
        return arbTreeMap(ord, arbList(arbP2(ak, av)));
    }

    /**
     * Returns an arbitrary implementation for tree maps where the map size is the given arbitrary integer.
     */
    public static  Arbitrary> arbTreeMap(Ord ord, Arbitrary ak, Arbitrary av, Arbitrary ai) {
        Gen>> gl2 = ai.gen.bind(i -> {
            if (i < 0) {
                Bottom.error("Undefined: arbitrary natural is negative (" + i + ")");
            }
            return Gen.sequenceN(Math.max(i, 0), Arbitrary.arbP2(ak, av).gen);
        });
        return arbTreeMap(ord, arbitrary(gl2));
    }

    /**
     * Returns an arbitrary implementation for tree maps where the size is less than or equal to the max size.
     */
    public static  Arbitrary> arbTreeMap(Ord ord, Arbitrary ak, Arbitrary av, int maxSize) {
        if (maxSize < 0) {
            Bottom.error("Undefined: arbitrary natural is negative (" + maxSize + ")");
        }
        return arbTreeMap(ord, ak, av, arbitrary(Gen.choose(0, maxSize)));
    }

  /**
   * Returns an arbitrary implementation for tree sets.
   *
   * @param aa An arbitrary implementation for the type over which the tree set is defined.
   * @return An arbitrary implementation for tree sets.
   */
  public static  Arbitrary> arbTreeSet(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, TreeSet>() {
      public TreeSet f(final Array a) {
        return new TreeSet(a.toCollection());
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for vectors.
   *
   * @param aa An arbitrary implementation for the type over which the vector is defined.
   * @return An arbitrary implementation for vectors.
   */
  @SuppressWarnings({"UseOfObsoleteCollectionType"})
  public static  Arbitrary> arbVector(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, Vector>() {
      @SuppressWarnings({"UseOfObsoleteCollectionType"})
      public Vector f(final Array a) {
        return new Vector(a.toCollection());
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for weak hash maps.
   *
   * @param ak An arbitrary implementation for the type over which the weak hash map's keys are
   *           defined.
   * @param av An arbitrary implementation for the type over which the weak hash map's values are
   *           defined.
   * @return An arbitrary implementation for weak hash maps.
   */
  public static  Arbitrary> arbWeakHashMap(final Arbitrary ak, final Arbitrary av) {
    return arbitrary(arbHashtable(ak, av).gen.map(new F, WeakHashMap>() {
      @SuppressWarnings({"UseOfObsoleteCollectionType"})
      public WeakHashMap f(final Hashtable ht) {
        return new WeakHashMap(ht);
      }
    }));
  }

  // END java.util

  // BEGIN java.util.concurrent

  /**
   * Returns an arbitrary implementation for array blocking queues.
   *
   * @param aa An arbitrary implementation for the type over which the array blocking queue is
   *           defined.
   * @return An arbitrary implementation for array blocking queues.
   */
  public static  Arbitrary> arbArrayBlockingQueue(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.bind(arbInteger.gen, arbBoolean.gen,
                                           new F, F>>>() {
                                             public F>> f(final Array a) {
                                               return new F>>() {
                                                 public F> f(final Integer capacity) {
                                                   return new F>() {
                                                     public ArrayBlockingQueue f(final Boolean fair) {
                                                       return new ArrayBlockingQueue(a.length() + abs(capacity),
                                                                                        fair, a.toCollection());
                                                     }
                                                   };
                                                 }
                                               };
                                             }
                                           }));
  }

  /**
   * Returns an arbitrary implementation for concurrent hash maps.
   *
   * @param ak An arbitrary implementation for the type over which the concurrent hash map's keys
   *           are defined.
   * @param av An arbitrary implementation for the type over which the concurrent hash map's values
   *           are defined.
   * @return An arbitrary implementation for concurrent hash maps.
   */
  public static  Arbitrary> arbConcurrentHashMap(final Arbitrary ak,
                                                                               final Arbitrary av) {
    return arbitrary(arbHashtable(ak, av).gen.map(new F, ConcurrentHashMap>() {
      @SuppressWarnings({"UseOfObsoleteCollectionType"})
      public ConcurrentHashMap f(final Hashtable ht) {
        return new ConcurrentHashMap(ht);
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for concurrent linked queues.
   *
   * @param aa An arbitrary implementation for the type over which the concurrent linked queue is
   *           defined.
   * @return An arbitrary implementation for concurrent linked queues.
   */
  public static  Arbitrary> arbConcurrentLinkedQueue(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, ConcurrentLinkedQueue>() {
      public ConcurrentLinkedQueue f(final Array a) {
        return new ConcurrentLinkedQueue(a.toCollection());
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for copy-on-write array lists.
   *
   * @param aa An arbitrary implementation for the type over which the copy-on-write array list is
   *           defined.
   * @return An arbitrary implementation for copy-on-write array lists.
   */
  public static  Arbitrary> arbCopyOnWriteArrayList(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, CopyOnWriteArrayList>() {
      public CopyOnWriteArrayList f(final Array a) {
        return new CopyOnWriteArrayList(a.toCollection());
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for copy-on-write array sets.
   *
   * @param aa An arbitrary implementation for the type over which the copy-on-write array set is
   *           defined.
   * @return An arbitrary implementation for copy-on-write array sets.
   */
  public static  Arbitrary> arbCopyOnWriteArraySet(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, CopyOnWriteArraySet>() {
      public CopyOnWriteArraySet f(final Array a) {
        return new CopyOnWriteArraySet(a.toCollection());
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for delay queues.
   *
   * @param aa An arbitrary implementation for the type over which the delay queue is defined.
   * @return An arbitrary implementation for delay queues.
   */
  public static  Arbitrary> arbDelayQueue(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, DelayQueue>() {
      public DelayQueue f(final Array a) {
        return new DelayQueue(a.toCollection());
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for linked blocking queues.
   *
   * @param aa An arbitrary implementation for the type over which the linked blocking queue is
   *           defined.
   * @return An arbitrary implementation for linked blocking queues.
   */
  public static  Arbitrary> arbLinkedBlockingQueue(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, LinkedBlockingQueue>() {
      public LinkedBlockingQueue f(final Array a) {
        return new LinkedBlockingQueue(a.toCollection());
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for priority blocking queues.
   *
   * @param aa An arbitrary implementation for the type over which the priority blocking queue is
   *           defined.
   * @return An arbitrary implementation for priority blocking queues.
   */
  public static  Arbitrary> arbPriorityBlockingQueue(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.map(new F, PriorityBlockingQueue>() {
      public PriorityBlockingQueue f(final Array a) {
        return new PriorityBlockingQueue(a.toCollection());
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for priority blocking queues.
   *
   * @param aa An arbitrary implementation for the type over which the priority blocking queue is
   *           defined.
   * @return An arbitrary implementation for priority blocking queues.
   */
  public static  Arbitrary> arbSynchronousQueue(final Arbitrary aa) {
    return arbitrary(arbArray(aa).gen.bind(arbBoolean.gen, new F, F>>() {
      public F> f(final Array a) {
        return new F>() {
          public SynchronousQueue f(final Boolean fair) {
            final SynchronousQueue q = new SynchronousQueue(fair);
            q.addAll(a.toCollection());
            return q;
          }
        };
      }
    }));
  }

  // END java.util.concurrent

  // BEGIN java.sql

  /**
   * An arbitrary implementation for SQL dates.
   */
  public static final Arbitrary arbSQLDate = arbitrary(arbLong.gen.map(new F() {
    public java.sql.Date f(final Long i) {
      return new java.sql.Date(i);
    }
  }));

  /**
   * An arbitrary implementation for SQL times.
   */
  public static final Arbitrary Arbitrary> arbP1(final Arbitrary aa) {
    return arbitrary(aa.gen.map(new F>() {
      public P1 f(final A a) {
        return p(a);
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for product-2 values.
   *
   * @param aa An arbitrary implementation for one of the types over which the product-2 is
   *           defined.
   * @param ab An Arbitrary implementation for one of the types over which the product-2 is
   *           defined.
   * @return An arbitrary implementation for product-2 values.
   */
  public static  Arbitrary> arbP2(final Arbitrary aa, final Arbitrary ab) {
    return arbitrary(aa.gen.bind(ab.gen, new F>>() {
      public F> f(final A a) {
        return new F>() {
          public P2 f(final B b) {
            return p(a, b);
          }
        };
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for product-3 values.
   *
   * @param aa An arbitrary implementation for one of the types over which the product-3 is
   *           defined.
   * @param ab An Arbitrary implementation for one of the types over which the product-3 is
   *           defined.
   * @param ac An arbitrary implementation for one of the types over which the product-3 is
   *           defined.
   * @return An arbitrary implementation for product-3 values.
   */
  public static  Arbitrary> arbP3(final Arbitrary aa, final Arbitrary ab,
                                                       final Arbitrary ac) {
    return arbitrary(aa.gen.bind(ab.gen, ac.gen, new F>>>() {
      public F>> f(final A a) {
        return new F>>() {
          public F> f(final B b) {
            return new F>() {
              public P3 f(final C c) {
                return p(a, b, c);
              }
            };
          }
        };
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for product-4 values.
   *
   * @param aa An arbitrary implementation for one of the types over which the product-4 is
   *           defined.
   * @param ab An Arbitrary implementation for one of the types over which the product-4 is
   *           defined.
   * @param ac An arbitrary implementation for one of the types over which the product-4 is
   *           defined.
   * @param ad An arbitrary implementation for one of the types over which the product-4 is
   *           defined.
   * @return An arbitrary implementation for product-4 values.
   */
  public static  Arbitrary> arbP4(final Arbitrary aa, final Arbitrary ab,
                                                             final Arbitrary ac, final Arbitrary ad) {
    return arbitrary(aa.gen.bind(ab.gen, ac.gen, ad.gen, new F>>>>() {
      public F>>> f(final A a) {
        return new F>>>() {
          public F>> f(final B b) {
            return new F>>() {
              public F> f(final C c) {
                return new F>() {
                  public P4 f(final D d) {
                    return p(a, b, c, d);
                  }
                };
              }
            };
          }
        };
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for product-5 values.
   *
   * @param aa An arbitrary implementation for one of the types over which the product-5 is
   *           defined.
   * @param ab An Arbitrary implementation for one of the types over which the product-5 is
   *           defined.
   * @param ac An arbitrary implementation for one of the types over which the product-5 is
   *           defined.
   * @param ad An arbitrary implementation for one of the types over which the product-5 is
   *           defined.
   * @param ae An arbitrary implementation for one of the types over which the product-5 is
   *           defined.
   * @return An arbitrary implementation for product-5 values.
   */
  public static  Arbitrary> arbP5(final Arbitrary aa, final Arbitrary ab,
                                                                   final Arbitrary ac, final Arbitrary ad,
                                                                   final Arbitrary ae) {
    return arbitrary(aa.gen.bind(ab.gen, ac.gen, ad.gen, ae.gen, new F>>>>>() {
      public F>>>> f(final A a) {
        return new F>>>>() {
          public F>>> f(final B b) {
            return new F>>>() {
              public F>> f(final C c) {
                return new F>>() {
                  public F> f(final D d) {
                    return new F>() {
                      public P5 f(final E e) {
                        return p(a, b, c, d, e);
                      }
                    };
                  }
                };
              }
            };
          }
        };
      }
    }));
  }

  /**
   * Returns an arbitrary implementation for product-6 values.
   *
   * @param aa An arbitrary implementation for one of the types over which the product-6 is
   *           defined.
   * @param ab An Arbitrary implementation for one of the types over which the product-6 is
   *           defined.
   * @param ac An arbitrary implementation for one of the types over which the product-6 is
   *           defined.
   * @param ad An arbitrary implementation for one of the types over which the product-6 is
   *           defined.
   * @param ae An arbitrary implementation for one of the types over which the product-6 is
   *           defined.
   * @param af An arbitrary implementation for one of the types over which the product-7 is
   *           defined.
   * @return An arbitrary implementation for product-6 values.
   */
  public static  Arbitrary> arbP6(final Arbitrary aa, final Arbitrary ab,
                                                                           final Arbitrary ac, final Arbitrary ad,
                                                                           final Arbitrary ae,
                                                                           final Arbitrary af) {
    return arbitrary(aa.gen.bind(ab.gen, ac.gen, ad.gen, ae.gen, af.gen,
                                 new F>>>>>>() {
                                   public F>>>>> f(final A a) {
                                     return new F>>>>>() {
                                       public F>>>> f(final B b) {
                                         return new F>>>>() {
                                           public F>>> f(final C c) {
                                             return new F>>>() {
                                               public F>> f(final D d) {
                                                 return new F>>() {
                                                   public F> f(final E e) {
                                                     return new F>() {
                                                       public P6 f(final F$ f) {
                                                         return p(a, b, c, d, e, f);
                                                       }
                                                     };
                                                   }
                                                 };
                                               }
                                             };
                                           }
                                         };
                                       }
                                     };
                                   }
                                 }));
  }

  /**
   * Returns an arbitrary implementation for product-7 values.
   *
   * @param aa An arbitrary implementation for one of the types over which the product-7 is
   *           defined.
   * @param ab An Arbitrary implementation for one of the types over which the product-7 is
   *           defined.
   * @param ac An arbitrary implementation for one of the types over which the product-7 is
   *           defined.
   * @param ad An arbitrary implementation for one of the types over which the product-7 is
   *           defined.
   * @param ae An arbitrary implementation for one of the types over which the product-7 is
   *           defined.
   * @param af An arbitrary implementation for one of the types over which the product-7 is
   *           defined.
   * @param ag An arbitrary implementation for one of the types over which the product-8 is
   *           defined.
   * @return An arbitrary implementation for product-7 values.
   */
  public static  Arbitrary> arbP7(final Arbitrary aa,
                                                                                 final Arbitrary ab,
                                                                                 final Arbitrary ac,
                                                                                 final Arbitrary ad,
                                                                                 final Arbitrary ae,
                                                                                 final Arbitrary af,
                                                                                 final Arbitrary ag) {
    return arbitrary(aa.gen.bind(ab.gen, ac.gen, ad.gen, ae.gen, af.gen, ag.gen,
                                 new F>>>>>>>() {
                                   public F>>>>>> f(final A a) {
                                     return new F>>>>>>() {
                                       public F>>>>> f(final B b) {
                                         return new F>>>>>() {
                                           public F>>>> f(final C c) {
                                             return new F>>>>() {
                                               public F>>> f(final D d) {
                                                 return new F>>>() {
                                                   public F>> f(final E e) {
                                                     return new F>>() {
                                                       public F> f(final F$ f) {
                                                         return new F>() {
                                                           public P7 f(final G g) {
                                                             return p(a, b, c, d, e, f, g);
                                                           }
                                                         };
                                                       }
                                                     };
                                                   }
                                                 };
                                               }
                                             };
                                           }
                                         };
                                       }
                                     };
                                   }
                                 }));
  }

  /**
   * Returns an arbitrary implementation for product-8 values.
   *
   * @param aa An arbitrary implementation for one of the types over which the product-8 is
   *           defined.
   * @param ab An Arbitrary implementation for one of the types over which the product-8 is
   *           defined.
   * @param ac An arbitrary implementation for one of the types over which the product-8 is
   *           defined.
   * @param ad An arbitrary implementation for one of the types over which the product-8 is
   *           defined.
   * @param ae An arbitrary implementation for one of the types over which the product-8 is
   *           defined.
   * @param af An arbitrary implementation for one of the types over which the product-8 is
   *           defined.
   * @param ag An arbitrary implementation for one of the types over which the product-8 is
   *           defined.
   * @param ah An arbitrary implementation for one of the types over which the product-8 is
   *           defined.
   * @return An arbitrary implementation for product-8 values.
   */
  public static  Arbitrary> arbP8(final Arbitrary aa,
                                                                                       final Arbitrary ab,
                                                                                       final Arbitrary ac,
                                                                                       final Arbitrary ad,
                                                                                       final Arbitrary ae,
                                                                                       final Arbitrary af,
                                                                                       final Arbitrary ag,
                                                                                       final Arbitrary ah) {
    return arbitrary(aa.gen.bind(ab.gen, ac.gen, ad.gen, ae.gen, af.gen, ag.gen, ah.gen,
                                 new F>>>>>>>>() {
                                   public F>>>>>>> f(
                                       final A a) {
                                     return new F>>>>>>>() {
                                       public F>>>>>> f(
                                           final B b) {
                                         return new F>>>>>>() {
                                           public F>>>>> f(
                                               final C c) {
                                             return new F>>>>>() {
                                               public F>>>> f(
                                                   final D d) {
                                                 return new F>>>>() {
                                                   public F>>> f(final E e) {
                                                     return new F>>>() {
                                                       public F>> f(final F$ f) {
                                                         return new F>>() {
                                                           public F> f(final G g) {
                                                             return new F>() {
                                                               public P8 f(final H h) {
                                                                 return p(a, b, c, d, e, f, g, h);
                                                               }
                                                             };
                                                           }
                                                         };
                                                       }
                                                     };
                                                   }
                                                 };
                                               }
                                             };
                                           }
                                         };
                                       }
                                     };
                                   }
                                 }));
  }
}