changeset 0:fe80c1edf1be

add getLoop
author tatsuki
date Fri, 20 Mar 2015 21:04:03 +0900
parents
children 8ed7d71e8617
files src/main/java/fj/Bottom.java src/main/java/fj/Class.java src/main/java/fj/Digit.java src/main/java/fj/Effect.java src/main/java/fj/Equal.java src/main/java/fj/F.java src/main/java/fj/F1Functions.java src/main/java/fj/F2.java src/main/java/fj/F2Functions.java src/main/java/fj/F3.java src/main/java/fj/F3Functions.java src/main/java/fj/F4.java src/main/java/fj/F4Functions.java src/main/java/fj/F5.java src/main/java/fj/F5Functions.java src/main/java/fj/F6.java src/main/java/fj/F6Functions.java src/main/java/fj/F7.java src/main/java/fj/F7Functions.java src/main/java/fj/F8.java src/main/java/fj/F8Functions.java src/main/java/fj/Function.java src/main/java/fj/Hash.java src/main/java/fj/LcgRng.java src/main/java/fj/Monoid.java src/main/java/fj/Ord.java src/main/java/fj/Ordering.java src/main/java/fj/P.java src/main/java/fj/P1.java src/main/java/fj/P2.java src/main/java/fj/P3.java src/main/java/fj/P4.java src/main/java/fj/P5.java src/main/java/fj/P6.java src/main/java/fj/P7.java src/main/java/fj/P8.java src/main/java/fj/Primitive.java src/main/java/fj/Rng.java src/main/java/fj/Semigroup.java src/main/java/fj/Show.java src/main/java/fj/Try.java src/main/java/fj/TryEffect.java src/main/java/fj/Unit.java src/main/java/fj/control/Trampoline.java src/main/java/fj/control/db/Connector.java src/main/java/fj/control/db/DB.java src/main/java/fj/control/db/DbState.java src/main/java/fj/control/db/package-info.java src/main/java/fj/control/package-info.java src/main/java/fj/control/parallel/Actor.java src/main/java/fj/control/parallel/Callables.java src/main/java/fj/control/parallel/ParModule.java src/main/java/fj/control/parallel/Promise.java src/main/java/fj/control/parallel/Strategy.java src/main/java/fj/control/parallel/package-info.java src/main/java/fj/data/$.java src/main/java/fj/data/Array.java src/main/java/fj/data/Conversions.java src/main/java/fj/data/Either.java src/main/java/fj/data/Enumerator.java src/main/java/fj/data/HashMap.java src/main/java/fj/data/HashSet.java src/main/java/fj/data/IO.java src/main/java/fj/data/IOFunctions.java src/main/java/fj/data/IterableW.java src/main/java/fj/data/Iteratee.java src/main/java/fj/data/Java.java src/main/java/fj/data/LazyString.java src/main/java/fj/data/List.java src/main/java/fj/data/Natural.java src/main/java/fj/data/NonEmptyList.java src/main/java/fj/data/Option.java src/main/java/fj/data/Reader.java src/main/java/fj/data/SafeIO.java src/main/java/fj/data/Seq.java src/main/java/fj/data/Set.java src/main/java/fj/data/State.java src/main/java/fj/data/Stream.java src/main/java/fj/data/Tree.java src/main/java/fj/data/TreeMap.java src/main/java/fj/data/TreeZipper.java src/main/java/fj/data/Validation.java src/main/java/fj/data/Writer.java src/main/java/fj/data/Zipper.java src/main/java/fj/data/fingertrees/Deep.java src/main/java/fj/data/fingertrees/Digit.java src/main/java/fj/data/fingertrees/Empty.java src/main/java/fj/data/fingertrees/FingerTree.java src/main/java/fj/data/fingertrees/Four.java src/main/java/fj/data/fingertrees/MakeTree.java src/main/java/fj/data/fingertrees/Measured.java src/main/java/fj/data/fingertrees/Node.java src/main/java/fj/data/fingertrees/Node2.java src/main/java/fj/data/fingertrees/Node3.java src/main/java/fj/data/fingertrees/One.java src/main/java/fj/data/fingertrees/Single.java src/main/java/fj/data/fingertrees/Three.java src/main/java/fj/data/fingertrees/Two.java src/main/java/fj/data/fingertrees/package-info.java src/main/java/fj/data/hlist/HList.java src/main/java/fj/data/hlist/HPre.java src/main/java/fj/data/hlist/package-info.java src/main/java/fj/data/package-info.java src/main/java/fj/data/vector/V.java src/main/java/fj/data/vector/V2.java src/main/java/fj/data/vector/V3.java src/main/java/fj/data/vector/V4.java src/main/java/fj/data/vector/V5.java src/main/java/fj/data/vector/V6.java src/main/java/fj/data/vector/V7.java src/main/java/fj/data/vector/V8.java src/main/java/fj/data/vector/package-info.java src/main/java/fj/function/BigIntegers.java src/main/java/fj/function/Booleans.java src/main/java/fj/function/Characters.java src/main/java/fj/function/Doubles.java src/main/java/fj/function/Effect0.java src/main/java/fj/function/Effect1.java src/main/java/fj/function/Effect2.java src/main/java/fj/function/Effect3.java src/main/java/fj/function/Effect4.java src/main/java/fj/function/Effect5.java src/main/java/fj/function/Effect6.java src/main/java/fj/function/Effect7.java src/main/java/fj/function/Effect8.java src/main/java/fj/function/Integers.java src/main/java/fj/function/Longs.java src/main/java/fj/function/Strings.java src/main/java/fj/function/Try0.java src/main/java/fj/function/Try1.java src/main/java/fj/function/Try2.java src/main/java/fj/function/Try3.java src/main/java/fj/function/Try4.java src/main/java/fj/function/Try5.java src/main/java/fj/function/Try6.java src/main/java/fj/function/Try7.java src/main/java/fj/function/Try8.java src/main/java/fj/function/TryEffect0.java src/main/java/fj/function/TryEffect1.java src/main/java/fj/function/TryEffect2.java src/main/java/fj/function/TryEffect3.java src/main/java/fj/function/TryEffect4.java src/main/java/fj/function/TryEffect5.java src/main/java/fj/function/TryEffect6.java src/main/java/fj/function/TryEffect7.java src/main/java/fj/function/TryEffect8.java src/main/java/fj/function/Visitor.java src/main/java/fj/function/package-info.java src/main/java/fj/package-info.java src/main/java/fj/parser/Parser.java src/main/java/fj/parser/Result.java src/main/java/fj/parser/package-info.java src/main/java/fj/test/Arbitrary.java src/main/java/fj/test/Arg.java src/main/java/fj/test/Bool.java src/main/java/fj/test/CheckResult.java src/main/java/fj/test/Coarbitrary.java src/main/java/fj/test/Gen.java src/main/java/fj/test/Property.java src/main/java/fj/test/Rand.java src/main/java/fj/test/Result.java src/main/java/fj/test/Shrink.java src/main/java/fj/test/Variant.java src/main/java/fj/test/package-info.java src/main/java/fj/test/reflect/Category.java src/main/java/fj/test/reflect/Check.java src/main/java/fj/test/reflect/CheckParams.java src/main/java/fj/test/reflect/Main.java src/main/java/fj/test/reflect/Name.java src/main/java/fj/test/reflect/NoCheck.java src/main/java/fj/test/reflect/package-info.java src/test/java/fj/MemoisationTest.java src/test/java/fj/P2Test.java src/test/java/fj/data/JavaTest.java src/test/java/fj/data/ReaderTest.java src/test/java/fj/data/StateTest.java src/test/java/fj/data/TestRngState.java src/test/java/fj/data/TestTreeMap.java src/test/java/fj/data/WriterTest.java src/test/java/fj/data/test/PropertyAssert.java src/test/java/fj/data/test/TestCheck.java src/test/java/fj/data/test/TestNull.java src/test/java/fj/function/TestEffect.java
diffstat 183 files changed, 47917 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/Bottom.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,109 @@
+package fj;
+
+/**
+ * Represents the bottom _|_ value.
+ *
+ * @version %build.number%
+ */
+public final class Bottom {
+  private Bottom() {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * Returns an error to represent undefinedness in a computation.
+   *
+   * @return An error to represent undefinedness in a computation.
+   */
+  public static Error undefined() {
+    return error("undefined");
+  }
+
+  /**
+   * Returns an error to represent undefinedness in a computation with early failure using the given
+   * message.
+   *
+   * @param s The message to fail with.
+   * @return An error to represent undefinedness in a computation with early failure using the given
+   *         message.
+   */
+  public static Error error(final String s) {
+    throw new Error(s);
+  }
+
+  /**
+   * Provides a thunk that throws an error using the given message when evaluated.
+   *
+   * @param s The message to fail with.
+   * @return A thunk that throws an error using the given message when evaluated.
+   */
+  public static <A> P1<A> error_(final String s) {
+    return new P1<A>() {
+      @Override public A _1() {
+        throw new Error(s);
+      }
+    };
+  }
+
+  /**
+   * Provides a function that throws an error using the given message, ignoring its argument.
+   *
+   * @param s The message to fail with.
+   * @return A function that throws an error using the given message, ignoring its argument.
+   */
+  public static <A, B> F<A, B> errorF(final String s) {
+    return new F<A, B>() {
+      public B f(final A a) {
+        throw new Error(s);
+      }
+    };
+  }
+
+  /**
+   * Represents a deconstruction failure that was non-exhaustive.
+   *
+   * @param a  The value being deconstructed.
+   * @param sa The rendering for the value being deconstructed.
+   * @return A deconstruction failure that was non-exhaustive.
+   */
+  public static <A> Error decons(final A a, final Show<A> sa) {
+    return error("Deconstruction failure on type " + a.getClass() + " with value " + sa.show(a).toString());
+  }
+
+  /**
+   * Represents a deconstruction failure that was non-exhaustive.
+   *
+   * @param c The type being deconstructed.
+   * @return A deconstruction failure that was non-exhaustive.
+   */
+  @SuppressWarnings({"UnnecessaryFullyQualifiedName"})
+  public static <A> Error decons(final java.lang.Class<A> c) {
+    return error("Deconstruction failure on type " + c);
+  }
+
+  /**
+   * A function that returns the <code>toString</code> for a throwable.
+   *
+   * @return A function that returns the <code>toString</code> for a throwable.
+   */
+  public static <T extends Throwable> F<T, String> eToString() {
+    return new F<T, String>() {
+      public String f(final Throwable t) {
+        return t.toString();
+      }
+    };
+  }
+
+  /**
+   * A function that returns the <code>getMessage</code> for a throwable.
+   *
+   * @return A function that returns the <code>getMessage</code> for a throwable.
+   */
+  public static <T extends Throwable> F<T, String> eMessage() {
+    return new F<T, String>() {
+      public String f(final Throwable t) {
+        return t.getMessage();
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/Class.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,135 @@
+package fj;
+
+import fj.data.List;
+import static fj.data.List.unfold;
+import fj.data.Option;
+import static fj.data.Option.none;
+import static fj.data.Option.some;
+import fj.data.Tree;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+/**
+ * A wrapper for a {@link java.lang.Class} that provides additional methods.
+ *
+ * @version %build.number%
+ */
+public final class Class<T> {
+  private final java.lang.Class<T> c;
+
+  private Class(final java.lang.Class<T> c) {
+    this.c = c;
+  }
+
+  /**
+   * Returns the inheritance hierarchy of this class.
+   *
+   * @return The inheritance hierarchy of this class.
+   */
+  public List<Class<? super T>> inheritance() {
+    return unfold(
+        new F<java.lang.Class<? super T>, Option<P2<java.lang.Class<? super T>, java.lang.Class<? super T>>>>() {
+          public Option<P2<java.lang.Class<? super T>, java.lang.Class<? super T>>> f(
+              final java.lang.Class<? super T> c) {
+            if (c == null)
+              return none();
+            else {
+              final P2<java.lang.Class<? super T>, java.lang.Class<? super T>> p =
+                  new P2<java.lang.Class<? super T>, java.lang.Class<? super T>>() {
+                    public java.lang.Class<? super T> _1() {
+                      return c;
+                    }
+
+                    @SuppressWarnings({"unchecked"})
+                    public java.lang.Class<? super T> _2() {
+                      return c.getSuperclass();
+                    }
+                  };
+              return some(p);
+            }
+          }
+        }, c).map(new F<java.lang.Class<? super T>, Class<? super T>>() {
+      public Class<? super T> f(final java.lang.Class<? super T> c) {
+        return clas(c);
+      }
+    });
+  }
+
+  /**
+   * Provides this class's type parameter information as a Tree of the type expression.
+   * Only descends into Parameterized classes. Non-abstract classes, or classes that don't implement an interface,
+   * are treated as raw types. Arrays, Type Variables, and Wildcards are treated as opaque Types.
+   *
+   * @return The rose tree representing the type expression for this class.
+   */
+  public Tree<Type> classParameters() {
+    return typeParameterTree(c);
+  }
+
+  /**
+   * Provides this class's superclass type parameter information as a Tree of the type expression.
+   * Only descends into Parameterized classes. Non-abstract classes, or classes that don't implement an interface,
+   * are treated as raw types. Arrays, Type Variables, and Wildcards are treated as opaque Types.
+   *
+   * @return The Tree representing the type expression for this class's superclass.
+   */
+  public Tree<Type> superclassParameters() {
+    return typeParameterTree(c.getGenericSuperclass());
+  }
+
+  /**
+   * Provides this class's interface type parameter information as a list of trees.
+   *
+   * @return A list of trees representing the type expressions for this class's interfaces.
+   */
+  public List<Tree<Type>> interfaceParameters() {
+    List<Tree<Type>> ts = List.nil();
+    for (final Type t : c.getInterfaces()) {
+      ts = ts.snoc(typeParameterTree(t));
+    }
+    return ts;
+  }
+
+  /**
+   * Provides type parameter information as a Tree of the type expression.
+   * Only descends into Parameterized classes. Non-abstract classes, or classes that don't implement an interface,
+   * are treated as raw types. Arrays, Type Variables, and Wildcards are treated as opaque Types.
+   *
+   * @param t The type (class) for which to get the generic type information.
+   * @return Type parameter information as a rose tree of the type expression.
+   */
+  public static Tree<Type> typeParameterTree(final Type t) {
+    List<Tree<Type>> typeArgs = List.nil();
+    final Tree<Type> types;
+    if (t instanceof ParameterizedType) {
+      final ParameterizedType pt = (ParameterizedType) t;
+      for (final Type arg : pt.getActualTypeArguments()) {
+        typeArgs = typeArgs.snoc(typeParameterTree(arg));
+      }
+      types = Tree.node(pt.getRawType(), typeArgs);
+    } else {
+      types = Tree.node(t, List.<Tree<Type>>nil());
+    }
+    return types;
+  }
+
+  /**
+   * Returns the underlying class.
+   *
+   * @return The underlying class.
+   */
+  public java.lang.Class<T> clas() {
+    return c;
+  }
+
+  /**
+   * Constructs a class from the given argument.
+   *
+   * @param c The argument to construct this class with.
+   * @return A class from the given argument.
+   */
+  public static <T> Class<T> clas(final java.lang.Class<T> c) {
+    return new Class<T>(c);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/Digit.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,211 @@
+package fj;
+
+import fj.data.Option;
+import static fj.data.Option.some;
+import static fj.data.Option.none;
+
+/**
+ * The digits zero to nine.
+ *
+ * @version %build.number%
+ */
+public enum Digit {
+  /**
+   * Zero.
+   */
+  _0,
+
+  /**
+   * One.
+   */
+  _1,
+
+  /**
+   * Two.
+   */
+  _2,
+
+  /**
+   * Three.
+   */
+  _3,
+
+  /**
+   * Four.
+   */
+  _4,
+
+  /**
+   * Five.
+   */
+  _5,
+
+  /**
+   * Six.
+   */
+  _6,
+
+  /**
+   * Seven.
+   */
+  _7,
+
+  /**
+   * Eight.
+   */
+  _8,
+
+  /**
+   * Nine.
+   */
+  _9;
+
+  /**
+   * Converts this digit to a long.
+   *
+   * @return A long for this digit.
+   */
+  public long toLong() {
+    switch (this) {
+      case _0:
+        return 0L;
+      case _1:
+        return 1L;
+      case _2:
+        return 2L;
+      case _3:
+        return 3L;
+      case _4:
+        return 4L;
+      case _5:
+        return 5L;
+      case _6:
+        return 6L;
+      case _7:
+        return 7L;
+      case _8:
+        return 8L;
+      default:
+        return 9L;
+    }
+  }
+
+  /**
+   * Converts this digit to a character.
+   *
+   * @return A character for this digit.
+   */
+  public char toChar() {
+    switch (this) {
+      case _0:
+        return '0';
+      case _1:
+        return '1';
+      case _2:
+        return '2';
+      case _3:
+        return '3';
+      case _4:
+        return '4';
+      case _5:
+        return '5';
+      case _6:
+        return '6';
+      case _7:
+        return '7';
+      case _8:
+        return '8';
+      default:
+        return '9';
+    }
+  }
+
+  /**
+   * Converts the right-most digit in the given long value to a digit.
+   *
+   * @param i The long to convert.
+   * @return The right-most digit in the given long value as a digit.
+   */
+  public static Digit fromLong(final long i) {
+    final long x = Math.abs(i) % 10L;
+    return x == 0L ? _0 :
+        x == 1L ? _1 :
+            x == 2L ? _2 :
+                x == 3L ? _3 :
+                    x == 4L ? _4 :
+                        x == 5L ? _5 :
+                            x == 6L ? _6 :
+                                x == 7L ? _7 :
+                                    x == 8L ? _8 :
+                                        _9;
+  }
+
+  /**
+   * Converts the given character in the given long value to a digit.
+   *
+   * @param c The character to convert.
+   * @return The character in the given long value as a digit.
+   */
+  public static Option<Digit> fromChar(final char c) {
+    switch (c) {
+      case '0':
+        return some(_0);
+      case '1':
+        return some(_1);
+      case '2':
+        return some(_2);
+      case '3':
+        return some(_3);
+      case '4':
+        return some(_4);
+      case '5':
+        return some(_5);
+      case '6':
+        return some(_6);
+      case '7':
+        return some(_7);
+      case '8':
+        return some(_8);
+      case '9':
+        return some(_9);
+      default:
+        return none();
+    }
+  }
+
+  /**
+   * First-class conversion from digit to a long.
+   */
+  public static final F<Digit, Long> toLong = new F<Digit, Long>() {
+    public Long f(final Digit d) {
+      return d.toLong();
+    }
+  };
+
+  /**
+   * First-class conversion from a long to a digit.
+   */
+  public static final F<Long, Digit> fromLong = new F<Long, Digit>() {
+    public Digit f(final Long i) {
+      return fromLong(i);
+    }
+  };
+
+  /**
+   * First-class conversion from a digit to a character.
+   */
+  public static final F<Digit, Character> toChar = new F<Digit, Character>() {
+    public Character f(final Digit d) {
+      return d.toChar();
+    }
+  };
+
+  /**
+   * First-class conversion from a character to a digit.
+   */
+  public static final F<Character, Option<Digit>> fromChar = new F<Character, Option<Digit>>() {
+    public Option<Digit> f(final Character c) {
+      return fromChar(c);
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/Effect.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,113 @@
+package fj;
+
+import fj.function.Effect0;
+import fj.function.Effect1;
+import fj.function.Effect2;
+import fj.function.Effect3;
+import fj.function.Effect4;
+import fj.function.Effect5;
+import fj.function.Effect6;
+import fj.function.Effect7;
+import fj.function.Effect8;
+
+import static fj.Unit.unit;
+
+/**
+ * Represents a side-effect.
+ *
+ * @version %build.number%
+ */
+public class Effect {
+
+	private Effect() {}
+
+    public static P1<Unit> f(Effect0 e) {
+        return P.lazy(u -> unit());
+    }
+
+    /**
+   * Returns a function for the given effect.
+   *
+   * @return The function using the given effect.
+   */
+  public static final <A> F<A, Unit> f(Effect1<A> e1) {
+    return a -> {
+        e1.f(a);
+        return unit();
+    };
+  }
+
+    public static <A, B> F2<A, B, Unit> f(Effect2<A, B> e) {
+        return (a, b) -> {
+            e.f(a, b);
+            return unit();
+        };
+    }
+
+    public static <A, B, C> F3<A, B, C, Unit> f(Effect3<A, B, C> e) {
+        return (a, b, c) -> {
+            e.f(a, b, c);
+            return unit();
+        };
+    }
+
+    public static <A, B, C, D> F4<A, B, C, D, Unit> f(Effect4<A, B, C, D> e) {
+        return (a, b, c, d) -> {
+            e.f(a, b, c, d);
+            return unit();
+        };
+    }
+
+    public static <A, B, C, D, E> F5<A, B, C, D, E, Unit> f(Effect5<A, B, C, D, E> z) {
+        return (a, b, c, d, e) -> {
+            z.f(a, b, c, d, e);
+            return unit();
+        };
+    }
+
+    public static <A, B, C, D, E, $F> F6<A, B, C, D, E, $F, Unit> f(Effect6<A, B, C, D, E, $F> z) {
+        return (a, b, c, d, e, f) -> {
+            z.f(a, b, c, d, e, f);
+            return unit();
+        };
+    }
+
+    public static <A, B, C, D, E, $F, G> F7<A, B, C, D, E, $F, G, Unit> f(Effect7<A, B, C, D, E, $F, G> z) {
+        return (a, b, c, d, e, f, g) -> {
+            z.f(a, b, c, d, e, f, g);
+            return unit();
+        };
+    }
+
+    public static <A, B, C, D, E, $F, G, H> F8<A, B, C, D, E, $F, G, H, Unit> f(Effect8<A, B, C, D, E, $F, G, H> z) {
+        return (a, b, c, d, e, f, g, h) -> {
+            z.f(a, b, c, d, e, f, g, h);
+            return unit();
+        };
+    }
+
+    /**
+   * A contra-variant functor on effect.
+   *
+   * @param f The function to map over the effect.
+   * @return An effect after a contra-variant map.
+   */
+  public final <A, B> Effect1<B> comap(Effect1<A> e1, final F<B, A> f) {
+    return new Effect1<B>() {
+      public void f(final B b) {
+        e1.f(f.f(b));
+      }
+    };
+  }
+  
+  public static <A> Effect1<A> lazy(final F<A, Unit> f) {
+    return new Effect1<A>() {
+      public void f(final A a) {
+        f.f(a);
+      }
+    };
+  }
+
+//	public static <A> void f(Effect1<A> )
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/Equal.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,667 @@
+package fj;
+
+import static fj.Function.curry;
+
+import fj.data.*;
+import fj.data.hlist.HList;
+import fj.data.vector.V2;
+import fj.data.vector.V3;
+import fj.data.vector.V4;
+import fj.data.vector.V5;
+import fj.data.vector.V6;
+import fj.data.vector.V7;
+import fj.data.vector.V8;
+
+import java.math.BigInteger;
+import java.math.BigDecimal;
+
+/**
+ * Tests for equality between two objects.
+ *
+ * @version %build.number%
+ */
+public final class Equal<A> {
+  private final F<A, F<A, Boolean>> f;
+
+  private Equal(final F<A, F<A, Boolean>> f) {
+    this.f = f;
+  }
+
+  /**
+   * Returns <code>true</code> if the two given arguments are equal, <code>false</code> otherwise.
+   *
+   * @param a1 An object to test for equality against another.
+   * @param a2 An object to test for equality against another.
+   * @return <code>true</code> if the two given arguments are equal, <code>false</code> otherwise.
+   */
+  public boolean eq(final A a1, final A a2) {
+    return f.f(a1).f(a2);
+  }
+
+  /**
+   * First-class equality check.
+   *
+   * @return A function that returns <code>true</code> if the two given arguments are equal.
+   */
+  public F2<A, A, Boolean> eq() {
+    return new F2<A, A, Boolean>() {
+      public Boolean f(final A a, final A a1) {
+        return eq(a, a1);
+      }
+    };
+  }
+
+  /**
+   * Partially applied equality check.
+   *
+   * @param a An object to test for equality against another.
+   * @return A function that returns <code>true</code> if the given argument equals the argument to this method.
+   */
+  public F<A, Boolean> eq(final A a) {
+    return new F<A, Boolean>() {
+      public Boolean f(final A a1) {
+        return eq(a, a1);
+      }
+    };
+  }
+
+  /**
+   * Maps the given function across this equal as a contra-variant functor.
+   *
+   * @param f The function to map.
+   * @return A new equal.
+   */
+  public <B> Equal<B> comap(final F<B, A> f) {
+    return equal(F1Functions.o(F1Functions.o(F1Functions.<B, A, Boolean>andThen(f), this.f), f));
+  }
+
+  /**
+   * Constructs an equal instance from the given function.
+   *
+   * @param f The function to construct the equal with.
+   * @return An equal instance from the given function.
+   */
+  public static <A> Equal<A> equal(final F<A, F<A, Boolean>> f) {
+    return new Equal<A>(f);
+  }
+
+  /**
+   * Returns an equal instance that uses the {@link Object#equals(Object)} method to test for
+   * equality.
+   *
+   * @return An equal instance that uses the {@link Object#equals(Object)} method to test for
+   *         equality.
+   */
+  public static <A> Equal<A> anyEqual() {
+    return new Equal<A>(new F<A, F<A, Boolean>>() {
+      public F<A, Boolean> f(final A a1) {
+        return new F<A, Boolean>() {
+          public Boolean f(final A a2) {
+            return a1.equals(a2);
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An equal instance for the <code>boolean</code> type.
+   */
+  public static final Equal<Boolean> booleanEqual = anyEqual();
+
+  /**
+   * An equal instance for the <code>byte</code> type.
+   */
+  public static final Equal<Byte> byteEqual = anyEqual();
+
+  /**
+   * An equal instance for the <code>char</code> type.
+   */
+  public static final Equal<Character> charEqual = anyEqual();
+
+  /**
+   * An equal instance for the <code>double</code> type.
+   */
+  public static final Equal<Double> doubleEqual = anyEqual();
+
+  /**
+   * An equal instance for the <code>float</code> type.
+   */
+  public static final Equal<Float> floatEqual = anyEqual();
+
+  /**
+   * An equal instance for the <code>int</code> type.
+   */
+  public static final Equal<Integer> intEqual = anyEqual();
+
+  /**
+   * An equal instance for the <code>BigInteger</code> type.
+   */
+  public static final Equal<BigInteger> bigintEqual = anyEqual();
+
+  /**
+   * An equal instance for the <code>BigDecimal</code> type.
+   */
+  public static final Equal<BigDecimal> bigdecimalEqual = anyEqual();
+
+  /**
+   * An equal instance for the <code>long</code> type.
+   */
+  public static final Equal<Long> longEqual = anyEqual();
+
+  /**
+   * An equal instance for the <code>short</code> type.
+   */
+  public static final Equal<Short> shortEqual = anyEqual();
+
+  /**
+   * An equal instance for the {@link String} type.
+   */
+  public static final Equal<String> stringEqual = anyEqual();
+
+  /**
+   * An equal instance for the {@link StringBuffer} type.
+   */
+  public static final Equal<StringBuffer> stringBufferEqual =
+      new Equal<StringBuffer>(new F<StringBuffer, F<StringBuffer, Boolean>>() {
+        public F<StringBuffer, Boolean> f(final StringBuffer sb1) {
+          return new F<StringBuffer, Boolean>() {
+            public Boolean f(final StringBuffer sb2) {
+              if (sb1.length() == sb2.length()) {
+                for (int i = 0; i < sb1.length(); i++)
+                  if (sb1.charAt(i) != sb2.charAt(i))
+                    return false;
+                return true;
+              } else
+                return false;
+            }
+          };
+        }
+      });
+
+  /**
+   * An equal instance for the {@link StringBuilder} type.
+   */
+  public static final Equal<StringBuilder> stringBuilderEqual =
+      new Equal<StringBuilder>(new F<StringBuilder, F<StringBuilder, Boolean>>() {
+        public F<StringBuilder, Boolean> f(final StringBuilder sb1) {
+          return new F<StringBuilder, Boolean>() {
+            public Boolean f(final StringBuilder sb2) {
+              if (sb1.length() == sb2.length()) {
+                for (int i = 0; i < sb1.length(); i++)
+                  if (sb1.charAt(i) != sb2.charAt(i))
+                    return false;
+                return true;
+              } else
+                return false;
+            }
+          };
+        }
+      });
+
+  /**
+   * An equal instance for the {@link Either} type.
+   *
+   * @param ea Equality across the left side of {@link Either}.
+   * @param eb Equality across the right side of {@link Either}.
+   * @return An equal instance for the {@link Either} type.
+   */
+  public static <A, B> Equal<Either<A, B>> eitherEqual(final Equal<A> ea, final Equal<B> eb) {
+    return new Equal<Either<A, B>>(new F<Either<A, B>, F<Either<A, B>, Boolean>>() {
+      public F<Either<A, B>, Boolean> f(final Either<A, B> e1) {
+        return new F<Either<A, B>, Boolean>() {
+          public Boolean f(final Either<A, B> e2) {
+            return e1.isLeft() && e2.isLeft() && ea.f.f(e1.left().value()).f(e2.left().value()) ||
+                   e1.isRight() && e2.isRight() && eb.f.f(e1.right().value()).f(e2.right().value());
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An equal instance for the {@link Validation} type.
+   *
+   * @param ea Equality across the failing side of {@link Validation}.
+   * @param eb Equality across the succeeding side of {@link Validation}.
+   * @return An equal instance for the {@link Validation} type.
+   */
+  public static <A, B> Equal<Validation<A, B>> validationEqual(final Equal<A> ea, final Equal<B> eb) {
+    return eitherEqual(ea, eb).comap(Validation.<A, B>either());
+  }
+
+  /**
+   * An equal instance for the {@link List} type.
+   *
+   * @param ea Equality across the elements of the list.
+   * @return An equal instance for the {@link List} type.
+   */
+  public static <A> Equal<List<A>> listEqual(final Equal<A> ea) {
+    return new Equal<List<A>>(new F<List<A>, F<List<A>, Boolean>>() {
+      public F<List<A>, Boolean> f(final List<A> a1) {
+        return new F<List<A>, Boolean>() {
+          public Boolean f(final List<A> a2) {
+            List<A> x1 = a1;
+            List<A> x2 = a2;
+
+            while (x1.isNotEmpty() && x2.isNotEmpty()) {
+              if (!ea.eq(x1.head(), x2.head()))
+                return false;
+
+              x1 = x1.tail();
+              x2 = x2.tail();
+            }
+
+            return x1.isEmpty() && x2.isEmpty();
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An equal instance for the {@link NonEmptyList} type.
+   *
+   * @param ea Equality across the elements of the non-empty list.
+   * @return An equal instance for the {@link NonEmptyList} type.
+   */
+  public static <A> Equal<NonEmptyList<A>> nonEmptyListEqual(final Equal<A> ea) {
+    return listEqual(ea).comap(NonEmptyList.<A>toList_());
+  }
+
+  /**
+   * An equal instance for the {@link Option} type.
+   *
+   * @param ea Equality across the element of the option.
+   * @return An equal instance for the {@link Option} type.
+   */
+  public static <A> Equal<Option<A>> optionEqual(final Equal<A> ea) {
+    return new Equal<Option<A>>(new F<Option<A>, F<Option<A>, Boolean>>() {
+      public F<Option<A>, Boolean> f(final Option<A> o1) {
+        return new F<Option<A>, Boolean>() {
+          public Boolean f(final Option<A> o2) {
+            return o1.isNone() && o2.isNone() ||
+                   o1.isSome() && o2.isSome() && ea.f.f(o1.some()).f(o2.some());
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An equal instance for the {@link Stream} type.
+   *
+   * @param ea Equality across the elements of the stream.
+   * @return An equal instance for the {@link Stream} type.
+   */
+  public static <A> Equal<Stream<A>> streamEqual(final Equal<A> ea) {
+    return new Equal<Stream<A>>(new F<Stream<A>, F<Stream<A>, Boolean>>() {
+      public F<Stream<A>, Boolean> f(final Stream<A> a1) {
+        return new F<Stream<A>, Boolean>() {
+          public Boolean f(final Stream<A> a2) {
+            Stream<A> x1 = a1;
+            Stream<A> x2 = a2;
+
+            while (x1.isNotEmpty() && x2.isNotEmpty()) {
+              if (!ea.eq(x1.head(), x2.head()))
+                return false;
+
+              x1 = x1.tail()._1();
+              x2 = x2.tail()._1();
+            }
+
+            return x1.isEmpty() && x2.isEmpty();
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An equal instance for the {@link Array} type.
+   *
+   * @param ea Equality across the elements of the array.
+   * @return An equal instance for the {@link Array} type.
+   */
+  public static <A> Equal<Array<A>> arrayEqual(final Equal<A> ea) {
+    return new Equal<Array<A>>(new F<Array<A>, F<Array<A>, Boolean>>() {
+      public F<Array<A>, Boolean> f(final Array<A> a1) {
+        return new F<Array<A>, Boolean>() {
+          public Boolean f(final Array<A> a2) {
+            if (a1.length() == a2.length()) {
+              for (int i = 0; i < a1.length(); i++) {
+                if (!ea.eq(a1.get(i), a2.get(i)))
+                  return false;
+              }
+              return true;
+            } else
+              return false;
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An equal instance for the {@link Tree} type.
+   *
+   * @param ea Equality across the elements of the tree.
+   * @return An equal instance for the {@link Tree} type.
+   */
+  public static <A> Equal<Tree<A>> treeEqual(final Equal<A> ea) {
+    return new Equal<Tree<A>>(curry(new F2<Tree<A>, Tree<A>, Boolean>() {
+      public Boolean f(final Tree<A> t1, final Tree<A> t2) {
+        return ea.eq(t1.root(), t2.root()) && p1Equal(streamEqual(treeEqual(ea))).eq(t2.subForest(), t1.subForest());
+      }
+    }));
+  }
+
+  /**
+   * An equal instance for a product-1.
+   *
+   * @param ea Equality across the first element of the product.
+   * @return An equal instance for a product-1.
+   */
+  public static <A> Equal<P1<A>> p1Equal(final Equal<A> ea) {
+    return new Equal<P1<A>>(new F<P1<A>, F<P1<A>, Boolean>>() {
+      public F<P1<A>, Boolean> f(final P1<A> p1) {
+        return new F<P1<A>, Boolean>() {
+          public Boolean f(final P1<A> p2) {
+            return ea.eq(p1._1(), p2._1());
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An equal instance for a product-2.
+   *
+   * @param ea Equality across the first element of the product.
+   * @param eb Equality across the second element of the product.
+   * @return An equal instance for a product-2.
+   */
+  public static <A, B> Equal<P2<A, B>> p2Equal(final Equal<A> ea, final Equal<B> eb) {
+    return new Equal<P2<A, B>>(new F<P2<A, B>, F<P2<A, B>, Boolean>>() {
+      public F<P2<A, B>, Boolean> f(final P2<A, B> p1) {
+        return new F<P2<A, B>, Boolean>() {
+          public Boolean f(final P2<A, B> p2) {
+            return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2());
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An equal instance for a product-3.
+   *
+   * @param ea Equality across the first element of the product.
+   * @param eb Equality across the second element of the product.
+   * @param ec Equality across the third element of the product.
+   * @return An equal instance for a product-3.
+   */
+  public static <A, B, C> Equal<P3<A, B, C>> p3Equal(final Equal<A> ea, final Equal<B> eb, final Equal<C> ec) {
+    return new Equal<P3<A, B, C>>(new F<P3<A, B, C>, F<P3<A, B, C>, Boolean>>() {
+      public F<P3<A, B, C>, Boolean> f(final P3<A, B, C> p1) {
+        return new F<P3<A, B, C>, Boolean>() {
+          public Boolean f(final P3<A, B, C> p2) {
+            return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3());
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An equal instance for a product-4.
+   *
+   * @param ea Equality across the first element of the product.
+   * @param eb Equality across the second element of the product.
+   * @param ec Equality across the third element of the product.
+   * @param ed Equality across the fourth element of the product.
+   * @return An equal instance for a product-4.
+   */
+  public static <A, B, C, D> Equal<P4<A, B, C, D>> p4Equal(final Equal<A> ea, final Equal<B> eb, final Equal<C> ec,
+                                                           final Equal<D> ed) {
+    return new Equal<P4<A, B, C, D>>(new F<P4<A, B, C, D>, F<P4<A, B, C, D>, Boolean>>() {
+      public F<P4<A, B, C, D>, Boolean> f(final P4<A, B, C, D> p1) {
+        return new F<P4<A, B, C, D>, Boolean>() {
+          public Boolean f(final P4<A, B, C, D> p2) {
+            return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
+                   ed.eq(p1._4(), p2._4());
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An equal instance for a product-5.
+   *
+   * @param ea Equality across the first element of the product.
+   * @param eb Equality across the second element of the product.
+   * @param ec Equality across the third element of the product.
+   * @param ed Equality across the fourth element of the product.
+   * @param ee Equality across the fifth element of the product.
+   * @return An equal instance for a product-5.
+   */
+  public static <A, B, C, D, E> Equal<P5<A, B, C, D, E>> p5Equal(final Equal<A> ea, final Equal<B> eb,
+                                                                 final Equal<C> ec, final Equal<D> ed,
+                                                                 final Equal<E> ee) {
+    return new Equal<P5<A, B, C, D, E>>(new F<P5<A, B, C, D, E>, F<P5<A, B, C, D, E>, Boolean>>() {
+      public F<P5<A, B, C, D, E>, Boolean> f(final P5<A, B, C, D, E> p1) {
+        return new F<P5<A, B, C, D, E>, Boolean>() {
+          public Boolean f(final P5<A, B, C, D, E> p2) {
+            return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
+                   ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5());
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An equal instance for a product-6.
+   *
+   * @param ea Equality across the first element of the product.
+   * @param eb Equality across the second element of the product.
+   * @param ec Equality across the third element of the product.
+   * @param ed Equality across the fourth element of the product.
+   * @param ee Equality across the fifth element of the product.
+   * @param ef Equality across the sixth element of the product.
+   * @return An equal instance for a product-6.
+   */
+  public static <A, B, C, D, E, F$> Equal<P6<A, B, C, D, E, F$>> p6Equal(final Equal<A> ea, final Equal<B> eb,
+                                                                         final Equal<C> ec, final Equal<D> ed,
+                                                                         final Equal<E> ee, final Equal<F$> ef) {
+    return new Equal<P6<A, B, C, D, E, F$>>(new F<P6<A, B, C, D, E, F$>, F<P6<A, B, C, D, E, F$>, Boolean>>() {
+      public F<P6<A, B, C, D, E, F$>, Boolean> f(final P6<A, B, C, D, E, F$> p1) {
+        return new F<P6<A, B, C, D, E, F$>, Boolean>() {
+          public Boolean f(final P6<A, B, C, D, E, F$> p2) {
+            return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
+                   ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()) && ef.eq(p1._6(), p2._6());
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An equal instance for a product-7.
+   *
+   * @param ea Equality across the first element of the product.
+   * @param eb Equality across the second element of the product.
+   * @param ec Equality across the third element of the product.
+   * @param ed Equality across the fourth element of the product.
+   * @param ee Equality across the fifth element of the product.
+   * @param ef Equality across the sixth element of the product.
+   * @param eg Equality across the seventh element of the product.
+   * @return An equal instance for a product-7.
+   */
+  public static <A, B, C, D, E, F$, G> Equal<P7<A, B, C, D, E, F$, G>> p7Equal(final Equal<A> ea, final Equal<B> eb,
+                                                                               final Equal<C> ec, final Equal<D> ed,
+                                                                               final Equal<E> ee, final Equal<F$> ef,
+                                                                               final Equal<G> eg) {
+    return new Equal<P7<A, B, C, D, E, F$, G>>(new F<P7<A, B, C, D, E, F$, G>, F<P7<A, B, C, D, E, F$, G>, Boolean>>() {
+      public F<P7<A, B, C, D, E, F$, G>, Boolean> f(final P7<A, B, C, D, E, F$, G> p1) {
+        return new F<P7<A, B, C, D, E, F$, G>, Boolean>() {
+          public Boolean f(final P7<A, B, C, D, E, F$, G> p2) {
+            return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
+                   ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()) && ef.eq(p1._6(), p2._6()) &&
+                   eg.eq(p1._7(), p2._7());
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An equal instance for a product-8.
+   *
+   * @param ea Equality across the first element of the product.
+   * @param eb Equality across the second element of the product.
+   * @param ec Equality across the third element of the product.
+   * @param ed Equality across the fourth element of the product.
+   * @param ee Equality across the fifth element of the product.
+   * @param ef Equality across the sixth element of the product.
+   * @param eg Equality across the seventh element of the product.
+   * @param eh Equality across the eighth element of the product.
+   * @return An equal instance for a product-8.
+   */
+  public static <A, B, C, D, E, F$, G, H> Equal<P8<A, B, C, D, E, F$, G, H>> p8Equal(final Equal<A> ea,
+                                                                                     final Equal<B> eb,
+                                                                                     final Equal<C> ec,
+                                                                                     final Equal<D> ed,
+                                                                                     final Equal<E> ee,
+                                                                                     final Equal<F$> ef,
+                                                                                     final Equal<G> eg,
+                                                                                     final Equal<H> eh) {
+    return new Equal<P8<A, B, C, D, E, F$, G, H>>(
+        new F<P8<A, B, C, D, E, F$, G, H>, F<P8<A, B, C, D, E, F$, G, H>, Boolean>>() {
+          public F<P8<A, B, C, D, E, F$, G, H>, Boolean> f(final P8<A, B, C, D, E, F$, G, H> p1) {
+            return new F<P8<A, B, C, D, E, F$, G, H>, Boolean>() {
+              public Boolean f(final P8<A, B, C, D, E, F$, G, H> p2) {
+                return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
+                       ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()) && ef.eq(p1._6(), p2._6()) &&
+                       eg.eq(p1._7(), p2._7()) && eh.eq(p1._8(), p2._8());
+              }
+            };
+          }
+        });
+  }
+
+  /**
+   * An equal instance for a vector-2.
+   *
+   * @param ea Equality across the elements of the vector.
+   * @return An equal instance for a vector-2.
+   */
+  public static <A> Equal<V2<A>> v2Equal(final Equal<A> ea) {
+    return streamEqual(ea).comap(V2.<A>toStream_());
+  }
+
+  /**
+   * An equal instance for a vector-3.
+   *
+   * @param ea Equality across the elements of the vector.
+   * @return An equal instance for a vector-3.
+   */
+  public static <A> Equal<V3<A>> v3Equal(final Equal<A> ea) {
+    return streamEqual(ea).comap(V3.<A>toStream_());
+  }
+
+  /**
+   * An equal instance for a vector-4.
+   *
+   * @param ea Equality across the elements of the vector.
+   * @return An equal instance for a vector-4.
+   */
+  public static <A> Equal<V4<A>> v4Equal(final Equal<A> ea) {
+    return streamEqual(ea).comap(V4.<A>toStream_());
+  }
+
+  /**
+   * An equal instance for a vector-5.
+   *
+   * @param ea Equality across the elements of the vector.
+   * @return An equal instance for a vector-5.
+   */
+  public static <A> Equal<V5<A>> v5Equal(final Equal<A> ea) {
+    return streamEqual(ea).comap(V5.<A>toStream_());
+  }
+
+  /**
+   * An equal instance for a vector-6.
+   *
+   * @param ea Equality across the elements of the vector.
+   * @return An equal instance for a vector-6.
+   */
+  public static <A> Equal<V6<A>> v6Equal(final Equal<A> ea) {
+    return streamEqual(ea).comap(V6.<A>toStream_());
+  }
+
+  /**
+   * An equal instance for a vector-7.
+   *
+   * @param ea Equality across the elements of the vector.
+   * @return An equal instance for a vector-7.
+   */
+  public static <A> Equal<V7<A>> v7Equal(final Equal<A> ea) {
+    return streamEqual(ea).comap(V7.<A>toStream_());
+  }
+
+  /**
+   * An equal instance for a vector-8.
+   *
+   * @param ea Equality across the elements of the vector.
+   * @return An equal instance for a vector-8.
+   */
+  public static <A> Equal<V8<A>> v8Equal(final Equal<A> ea) {
+    return streamEqual(ea).comap(V8.<A>toStream_());
+  }
+
+  /**
+   * An equal instance for lazy strings.
+   */
+  public static final Equal<LazyString> eq = streamEqual(charEqual).comap(LazyString.toStream);
+
+  /**
+   * An equal instance for the empty heterogeneous list.
+   */
+  public static final Equal<HList.HNil> hListEqual = anyEqual();
+
+  /**
+   * An equal instance for heterogeneous lists.
+   *
+   * @param e Equality for the first element of the list.
+   * @param l Equality for the rest of the list.
+   * @return an equal instance for a heterogeneous list.
+   */
+  public static <E, L extends HList<L>> Equal<HList.HCons<E, L>> hListEqual(final Equal<E> e, final Equal<L> l) {
+    return equal(curry(new F2<HList.HCons<E, L>, HList.HCons<E, L>, Boolean>() {
+      public Boolean f(final HList.HCons<E, L> c1, final HList.HCons<E, L> c2) {
+        return e.eq(c1.head(), c2.head()) && l.eq(c1.tail(), c2.tail());
+      }
+    }));
+  }
+
+  /**
+   * Equal instance for sets.
+   *
+   * @param e Equality for the set elements.
+   * @return An equal instance for sets.
+   */
+  public static <A> Equal<Set<A>> setEqual(final Equal<A> e) {
+    return equal(curry(new F2<Set<A>, Set<A>, Boolean>() {
+      public Boolean f(final Set<A> a, final Set<A> b) {
+        return streamEqual(e).eq(a.toStream(), b.toStream());
+      }
+    }));
+  }
+
+  public static <A, B> Equal<Writer<A, B>> writerEqual(Equal<A> eq1, Equal<B> eq2) {
+    return new Equal<Writer<A, B>>(w1 -> w2 -> Equal.p2Equal(eq1, eq2).eq(w1.run(), w2.run()));
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,50 @@
+package fj;
+
+import fj.control.parallel.Actor;
+import fj.control.parallel.Promise;
+import fj.control.parallel.Strategy;
+import fj.data.Array;
+import fj.data.Either;
+import fj.data.IterableW;
+import fj.data.List;
+import fj.data.NonEmptyList;
+import fj.data.Option;
+import fj.data.Set;
+import fj.data.Stream;
+import fj.data.Tree;
+import fj.data.TreeZipper;
+import fj.data.Validation;
+import fj.data.Zipper;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.PriorityQueue;
+import java.util.TreeSet;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.SynchronousQueue;
+
+import static fj.data.Option.some;
+import static fj.data.Stream.iterableStream;
+import static fj.data.Zipper.fromStream;
+
+/**
+ * A transformation or function from <code>A</code> to <code>B</code>. This type can be represented
+ * using the Java 7 closure syntax.
+ *
+ * @version %build.number%
+ */
+public interface F<A, B> {
+  /**
+   * Transform <code>A</code> to <code>B</code>.
+   *
+   * @param a The <code>A</code> to transform.
+   * @return The result of the transformation.
+   */
+  public abstract B f(A a);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F1Functions.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,846 @@
+package fj;
+
+import fj.control.parallel.Actor;
+import fj.control.parallel.Promise;
+import fj.control.parallel.Strategy;
+import fj.data.*;
+import fj.function.Try1;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.PriorityQueue;
+import java.util.TreeSet;
+import java.util.concurrent.*;
+
+import static fj.data.Option.some;
+import static fj.data.Stream.iterableStream;
+import static fj.data.Zipper.fromStream;
+
+/**
+ * Created by MarkPerry on 6/04/2014.
+ */
+public class F1Functions {
+
+
+    /**
+     * Function composition
+     *
+     * @param g A function to compose with this one.
+     * @return The composed function such that this function is applied last.
+     */
+    static public <A, B, C> F<C, B> o(final F<A, B> f, final F<C, A> g) {
+        return new F<C, B>() {
+            public B f(final C c) {
+                return f.f(g.f(c));
+            }
+        };
+    }
+
+    /**
+     * First-class function composition
+     *
+     * @return A function that composes this function with another.
+     */
+    static public <A, B,C> F<F<C, A>, F<C, B>> o(final F<A, B> f) {
+        return new F<F<C, A>, F<C, B>>() {
+            public F<C, B> f(final F<C, A> g) {
+                return o(f, g);
+            }
+        };
+    }
+
+    /**
+     * Function composition flipped.
+     *
+     * @param g A function with which to compose this one.
+     * @return The composed function such that this function is applied first.
+     */
+    @SuppressWarnings({"unchecked"})
+    static public <A, B, C> F<A, C> andThen(final F<A, B> f, final F<B, C> g) {
+        return o(g, f);
+    }
+
+    /**
+     * First-class composition flipped.
+     *
+     * @return A function that invokes this function and then a given function on the result.
+     */
+    static public <A, B, C> F<F<B, C>, F<A, C>> andThen(final F<A, B> f) {
+        return new F<F<B, C>, F<A, C>>() {
+            public F<A, C> f(final F<B, C> g) {
+                return andThen(f, g);
+            }
+        };
+    }
+
+    /**
+     * Binds a given function across this function (Reader Monad).
+     *
+     * @param g A function that takes the return value of this function as an argument, yielding a new function.
+     * @return A function that invokes this function on its argument and then the given function on the result.
+     */
+    static public <A, B, C> F<A, C> bind(final F<A, B> f, final F<B, F<A, C>> g) {
+        return new F<A, C>() {
+            @SuppressWarnings({"unchecked"})
+            public C f(final A a) {
+                return g.f(f.f(a)).f(a);
+            }
+        };
+    }
+
+    /**
+     * First-class function binding.
+     *
+     * @return A function that binds another function across this function.
+     */
+    static public <A, B, C> F<F<B, F<A, C>>, F<A, C>> bind(final F<A, B> f) {
+        return new F<F<B, F<A, C>>, F<A, C>>() {
+            public F<A, C> f(final F<B, F<A, C>> g) {
+                return bind(f, g);
+            }
+        };
+    }
+
+    /**
+     * Function application in an environment (Applicative Functor).
+     *
+     * @param g A function with the same argument type as this function, yielding a function that takes the return
+     *          value of this function.
+     * @return A new function that invokes the given function on its argument, yielding a new function that is then
+     *         applied to the result of applying this function to the argument.
+     */
+    static public <A, B, C> F<A, C> apply(final F<A, B> f, final F<A, F<B, C>> g) {
+        return new F<A, C>() {
+            @SuppressWarnings({"unchecked"})
+            public C f(final A a) {
+                return g.f(a).f(f.f(a));
+            }
+        };
+    }
+
+    /**
+     * First-class function application in an environment.
+     *
+     * @return A function that applies a given function within the environment of this function.
+     */
+    static public <A, B, C> F<F<A, F<B, C>>, F<A, C>> apply(final F<A, B> f) {
+        return new F<F<A, F<B, C>>, F<A, C>>() {
+            public F<A, C> f(final F<A, F<B, C>> g) {
+                return apply(f, g);
+            }
+        };
+    }
+
+    /**
+     * Applies this function over the arguments of another function.
+     *
+     * @param g The function over whose arguments to apply this function.
+     * @return A new function that invokes this function on its arguments before invoking the given function.
+     */
+    static public <A, B, C> F<A, F<A, C>> on(final F<A, B> f, final F<B, F<B, C>> g) {
+        return new F<A, F<A, C>>() {
+            public F<A, C> f(final A a1) {
+                return new F<A, C>() {
+                    @SuppressWarnings({"unchecked"})
+                    public C f(final A a2) {
+                        return g.f(f.f(a1)).f(f.f(a2));
+                    }
+                };
+            }
+        };
+    }
+
+
+    /**
+     * Applies this function over the arguments of another function.
+     *
+     * @return A function that applies this function over the arguments of another function.
+     */
+    static public <A, B, C> F<F<B, F<B, C>>, F<A, F<A, C>>> on(final F<A, B> f) {
+        return new F<F<B, F<B, C>>, F<A, F<A, C>>>() {
+            public F<A, F<A, C>> f(final F<B, F<B, C>> g) {
+                return on(f, g);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function so that it returns its result in a product-1. Kleisli arrow for P1.
+     *
+     * @return This function promoted to return its result in a product-1.
+     */
+    static public <A, B> F<A, P1<B>> lazy(final F<A, B> f) {
+        return new F<A, P1<B>>() {
+            public P1<B> f(final A a) {
+                return new P1<B>() {
+                    public B _1() {
+                        return f.f(a);
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Partial application.
+     *
+     * @param a The <code>A</code> to which to apply this function.
+     * @return The function partially applied to the given argument to return a lazy value.
+     */
+    static public <A, B> P1<B> f(final F<A, B> f, final A a) {
+        return P.lazy(u -> f.f(a));
+    }
+
+    /**
+     * Promotes this function to map over a product-1.
+     *
+     * @return This function promoted to map over a product-1.
+     */
+    static public <A, B> F<P1<A>, P1<B>> mapP1(final F<A, B> f) {
+        return new F<P1<A>, P1<B>>() {
+            public P1<B> f(final P1<A> p) {
+                return p.map(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function so that it returns its result in an Option. Kleisli arrow for Option.
+     *
+     * @return This function promoted to return its result in an Option.
+     */
+    static public <A, B> F<A, Option<B>> optionK(final F<A, B> f) {
+        return new F<A, Option<B>>() {
+            public Option<B> f(final A a) {
+                return some(f.f(a));
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to map over an optional value.
+     *
+     * @return This function promoted to map over an optional value.
+     */
+    static public <A, B> F<Option<A>, Option<B>> mapOption(final F<A, B> f) {
+        return new F<Option<A>, Option<B>>() {
+            public Option<B> f(final Option<A> o) {
+                return o.map(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function so that it returns its result in a List. Kleisli arrow for List.
+     *
+     * @return This function promoted to return its result in a List.
+     */
+    static public <A, B> F<A, List<B>> listK(final F<A, B> f) {
+        return new F<A, List<B>>() {
+            public List<B> f(final A a) {
+                return List.single(f.f(a));
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to map over a List.
+     *
+     * @return This function promoted to map over a List.
+     */
+    static public <A, B> F<List<A>, List<B>> mapList(final F<A, B> f) {
+        return new F<List<A>, List<B>>() {
+            public List<B> f(final List<A> x) {
+                return x.map(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function so that it returns its result in a Stream. Kleisli arrow for Stream.
+     *
+     * @return This function promoted to return its result in a Stream.
+     */
+    static public <A, B> F<A, Stream<B>> streamK(final F<A, B> f) {
+        return new F<A, Stream<B>>() {
+            public Stream<B> f(final A a) {
+                return Stream.single(f.f(a));
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to map over a Stream.
+     *
+     * @return This function promoted to map over a Stream.
+     */
+    static public <A, B> F<Stream<A>, Stream<B>> mapStream(final F<A, B> f) {
+        return new F<Stream<A>, Stream<B>>() {
+            public Stream<B> f(final Stream<A> x) {
+                return x.map(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function so that it returns its result in a Array. Kleisli arrow for Array.
+     *
+     * @return This function promoted to return its result in a Array.
+     */
+    static public <A, B> F<A, Array<B>> arrayK(final F<A, B> f) {
+        return new F<A, Array<B>>() {
+            public Array<B> f(final A a) {
+                return Array.single(f.f(a));
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to map over a Array.
+     *
+     * @return This function promoted to map over a Array.
+     */
+    static public <A, B> F<Array<A>, Array<B>> mapArray(final F<A, B> f) {
+        return new F<Array<A>, Array<B>>() {
+            public Array<B> f(final Array<A> x) {
+                return x.map(f);
+            }
+        };
+    }
+
+    /**
+     * Returns a function that comaps over a given actor.
+     *
+     * @return A function that comaps over a given actor.
+     */
+    static public <A, B> F<Actor<B>, Actor<A>> comapActor(final F<A, B> f) {
+        return new F<Actor<B>, Actor<A>>() {
+            public Actor<A> f(final Actor<B> a) {
+                return a.comap(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to a concurrent function that returns a Promise of a value.
+     *
+     * @param s A parallel strategy for concurrent execution.
+     * @return A concurrent function that returns a Promise of a value.
+     */
+    static public <A, B> F<A, Promise<B>> promiseK(final F<A, B> f, final Strategy<Unit> s) {
+        return Promise.promise(s, f);
+    }
+
+    /**
+     * Promotes this function to map over a Promise.
+     *
+     * @return This function promoted to map over Promises.
+     */
+    static public <A, B> F<Promise<A>, Promise<B>> mapPromise(final F<A, B> f) {
+        return new F<Promise<A>, Promise<B>>() {
+            public Promise<B> f(final Promise<A> p) {
+                return p.fmap(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function so that it returns its result on the left side of an Either.
+     * Kleisli arrow for the Either left projection.
+     *
+     * @return This function promoted to return its result on the left side of an Either.
+     */
+    @SuppressWarnings({"unchecked"})
+    static public <A, B, C> F<A, Either<B, C>> eitherLeftK(final F<A, B> f) {
+        return o(Either.<B, C>left_(), f);
+    }
+
+    /**
+     * Promotes this function so that it returns its result on the right side of an Either.
+     * Kleisli arrow for the Either right projection.
+     *
+     * @return This function promoted to return its result on the right side of an Either.
+     */
+    @SuppressWarnings({"unchecked"})
+    static public <A, B, C> F<A, Either<C, B>> eitherRightK(final F<A, B> f) {
+        return o(Either.<C, B>right_(), f);
+    }
+
+    /**
+     * Promotes this function to map over the left side of an Either.
+     *
+     * @return This function promoted to map over the left side of an Either.
+     */
+    @SuppressWarnings({"unchecked"})
+    static public <A, B, X> F<Either<A, X>, Either<B, X>> mapLeft(final F<A, B> f) {
+        return Either.<A, X, B>leftMap_().f(f);
+    }
+
+    /**
+     * Promotes this function to map over the right side of an Either.
+     *
+     * @return This function promoted to map over the right side of an Either.
+     */
+    @SuppressWarnings({"unchecked"})
+    static public <A, B, X> F<Either<X, A>, Either<X, B>> mapRight(final F<A, B> f) {
+        return Either.<X, A, B>rightMap_().f(f);
+    }
+
+    /**
+     * Returns a function that returns the left side of a given Either, or this function applied to the right side.
+     *
+     * @return a function that returns the left side of a given Either, or this function applied to the right side.
+     */
+    static public <A, B> F<Either<B, A>, B> onLeft(final F<A, B> f) {
+        return new F<Either<B, A>, B>() {
+            public B f(final Either<B, A> either) {
+                return either.left().on(f);
+            }
+        };
+    }
+
+    /**
+     * Returns a function that returns the right side of a given Either, or this function applied to the left side.
+     *
+     * @return a function that returns the right side of a given Either, or this function applied to the left side.
+     */
+    static public <A, B> F<Either<A, B>, B> onRight(final F<A, B> f) {
+        return new F<Either<A, B>, B>() {
+            public B f(final Either<A, B> either) {
+                return either.right().on(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to return its value in an Iterable.
+     *
+     * @return This function promoted to return its value in an Iterable.
+     */
+    @SuppressWarnings({"unchecked"})
+    static public <A, B> F<A, IterableW<B>> iterableK(final F<A, B> f) {
+        return IterableW.<A, B>arrow().f(f);
+    }
+
+    /**
+     * Promotes this function to map over Iterables.
+     *
+     * @return This function promoted to map over Iterables.
+     */
+    @SuppressWarnings({"unchecked"})
+    static public <A, B> F<Iterable<A>, IterableW<B>> mapIterable(final F<A, B> f) {
+        return F1Functions.o(IterableW.<A, B>map().f(f), IterableW.<A, Iterable<A>>wrap());
+    }
+
+    /**
+     * Promotes this function to return its value in a NonEmptyList.
+     *
+     * @return This function promoted to return its value in a NonEmptyList.
+     */
+    @SuppressWarnings({"unchecked"})
+    static public <A, B> F<A, NonEmptyList<B>> nelK(final F<A, B> f) {
+        return o(NonEmptyList.<B>nel(), f);
+    }
+
+    /**
+     * Promotes this function to map over a NonEmptyList.
+     *
+     * @return This function promoted to map over a NonEmptyList.
+     */
+    static public <A, B> F<NonEmptyList<A>, NonEmptyList<B>> mapNel(final F<A, B> f) {
+        return new F<NonEmptyList<A>, NonEmptyList<B>>() {
+            public NonEmptyList<B> f(final NonEmptyList<A> list) {
+                return list.map(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to return its value in a Set.
+     *
+     * @param o An order for the set.
+     * @return This function promoted to return its value in a Set.
+     */
+    static public <A, B> F<A, Set<B>> setK(final F<A, B> f, final Ord<B> o
+    ) {
+        return new F<A, Set<B>>() {
+            public Set<B> f(final A a) {
+                return Set.single(o, f.f(a));
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to map over a Set.
+     *
+     * @param o An order for the resulting set.
+     * @return This function promoted to map over a Set.
+     */
+    static public <A, B> F<Set<A>, Set<B>> mapSet(final F<A, B> f, final Ord<B> o) {
+        return new F<Set<A>, Set<B>>() {
+            public Set<B> f(final Set<A> set) {
+                return set.map(o, f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to return its value in a Tree.
+     *
+     * @return This function promoted to return its value in a Tree.
+     */
+    static public <A, B> F<A, Tree<B>> treeK(final F<A, B> f) {
+        return new F<A, Tree<B>>() {
+            public Tree<B> f(final A a) {
+                return Tree.leaf(f.f(a));
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to map over a Tree.
+     *
+     * @return This function promoted to map over a Tree.
+     */
+    @SuppressWarnings({"unchecked"})
+    static public <A, B> F<Tree<A>, Tree<B>> mapTree(final F<A, B> f) {
+        return Tree.<A, B>fmap_().f(f);
+    }
+
+    /**
+     * Returns a function that maps this function over a tree and folds it with the given monoid.
+     *
+     * @param m The monoid with which to fold the mapped tree.
+     * @return a function that maps this function over a tree and folds it with the given monoid.
+     */
+    static public <A, B> F<Tree<A>, B> foldMapTree(final F<A, B> f, final Monoid<B> m) {
+        return Tree.foldMap_(f, m);
+    }
+
+    /**
+     * Promotes this function to return its value in a TreeZipper.
+     *
+     * @return This function promoted to return its value in a TreeZipper.
+     */
+    static public <A, B> F<A, TreeZipper<B>> treeZipperK(final F<A, B> f) {
+        return andThen(treeK(f), TreeZipper.<B>fromTree());
+    }
+
+    /**
+     * Promotes this function to map over a TreeZipper.
+     *
+     * @return This function promoted to map over a TreeZipper.
+     */
+    static public <A, B> F<TreeZipper<A>, TreeZipper<B>> mapTreeZipper(final F<A, B> f) {
+        return new F<TreeZipper<A>, TreeZipper<B>>() {
+            public TreeZipper<B> f(final TreeZipper<A> zipper) {
+                return zipper.map(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function so that it returns its result on the failure side of a Validation.
+     * Kleisli arrow for the Validation failure projection.
+     *
+     * @return This function promoted to return its result on the failure side of a Validation.
+     */
+    static public <A, B, C> F<A, Validation<B, C>> failK(final F<A, B> f) {
+        return new F<A, Validation<B, C>>() {
+            public Validation<B, C> f(final A a) {
+                return Validation.fail(f.f(a));
+            }
+        };
+    }
+
+    /**
+     * Promotes this function so that it returns its result on the success side of an Validation.
+     * Kleisli arrow for the Validation success projection.
+     *
+     * @return This function promoted to return its result on the success side of an Validation.
+     */
+    static public <A, B, C> F<A, Validation<C, B>> successK(final F<A, B> f) {
+        return new F<A, Validation<C, B>>() {
+            public Validation<C, B> f(final A a) {
+                return Validation.success(f.f(a));
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to map over the failure side of a Validation.
+     *
+     * @return This function promoted to map over the failure side of a Validation.
+     */
+    static public <A, B, X> F<Validation<A, X>, Validation<B, X>> mapFail(final F<A, B> f) {
+        return new F<Validation<A, X>, Validation<B, X>>() {
+            public Validation<B, X> f(final Validation<A, X> validation) {
+                return validation.f().map(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to map over the success side of a Validation.
+     *
+     * @return This function promoted to map over the success side of a Validation.
+     */
+    static public <A, B, X> F<Validation<X, A>, Validation<X, B>> mapSuccess(final F<A, B> f) {
+        return new F<Validation<X, A>, Validation<X, B>>() {
+            public Validation<X, B> f(final Validation<X, A> validation) {
+                return validation.map(f);
+            }
+        };
+    }
+
+    /**
+     * Returns a function that returns the failure side of a given Validation,
+     * or this function applied to the success side.
+     *
+     * @return a function that returns the failure side of a given Validation,
+     *         or this function applied to the success side.
+     */
+    static public <A, B> F<Validation<B, A>, B> onFail(final F<A, B> f) {
+        return new F<Validation<B, A>, B>() {
+            public B f(final Validation<B, A> v) {
+                return v.f().on(f);
+            }
+        };
+    }
+
+    /**
+     * Returns a function that returns the success side of a given Validation,
+     * or this function applied to the failure side.
+     *
+     * @return a function that returns the success side of a given Validation,
+     *         or this function applied to the failure side.
+     */
+    static public <A, B> F<Validation<A, B>, B> onSuccess(final F<A, B> f) {
+        return new F<Validation<A, B>, B>() {
+            public B f(final Validation<A, B> v) {
+                return v.on(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to return its value in a Zipper.
+     *
+     * @return This function promoted to return its value in a Zipper.
+     */
+    static public <A, B> F<A, Zipper<B>> zipperK(final F<A, B> f) {
+        return andThen(streamK(f), new F<Stream<B>, Zipper<B>>() {
+            public Zipper<B> f(final Stream<B> stream) {
+                return fromStream(stream).some();
+            }
+        });
+    }
+
+    /**
+     * Promotes this function to map over a Zipper.
+     *
+     * @return This function promoted to map over a Zipper.
+     */
+    static public <A, B> F<Zipper<A>, Zipper<B>> mapZipper(final F<A, B> f) {
+        return new F<Zipper<A>, Zipper<B>>() {
+            public Zipper<B> f(final Zipper<A> zipper) {
+                return zipper.map(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to map over an Equal as a contravariant functor.
+     *
+     * @return This function promoted to map over an Equal as a contravariant functor.
+     */
+    static public <A, B> F<Equal<B>, Equal<A>> comapEqual(final F<A, B> f) {
+        return new F<Equal<B>, Equal<A>>() {
+            public Equal<A> f(final Equal<B> equal) {
+                return equal.comap(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to map over a Hash as a contravariant functor.
+     *
+     * @return This function promoted to map over a Hash as a contravariant functor.
+     */
+    static public <A, B> F<Hash<B>, Hash<A>> comapHash(final F<A, B> f) {
+        return new F<Hash<B>, Hash<A>>() {
+            public Hash<A> f(final Hash<B> hash) {
+                return hash.comap(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to map over a Show as a contravariant functor.
+     *
+     * @return This function promoted to map over a Show as a contravariant functor.
+     */
+    static public <A, B> F<Show<B>, Show<A>> comapShow(final F<A, B> f) {
+        return new F<Show<B>, Show<A>>() {
+            public Show<A> f(final Show<B> s) {
+                return s.comap(f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to map over the first element of a pair.
+     *
+     * @return This function promoted to map over the first element of a pair.
+     */
+    static public <A, B, C> F<P2<A, C>, P2<B, C>> mapFst(final F<A, B> f) {
+        return P2.map1_(f);
+    }
+
+    /**
+     * Promotes this function to map over the second element of a pair.
+     *
+     * @return This function promoted to map over the second element of a pair.
+     */
+    static public <A, B, C> F<P2<C, A>, P2<C, B>> mapSnd(final F<A, B> f) {
+        return P2.map2_(f);
+    }
+
+    /**
+     * Promotes this function to map over both elements of a pair.
+     *
+     * @return This function promoted to map over both elements of a pair.
+     */
+    static public <A, B> F<P2<A, A>, P2<B, B>> mapBoth(final F<A, B> f) {
+        return new F<P2<A, A>, P2<B, B>>() {
+            public P2<B, B> f(final P2<A, A> aap2) {
+                return P2.map(f, aap2);
+            }
+        };
+    }
+
+    /**
+     * Maps this function over a SynchronousQueue.
+     *
+     * @param as A SynchronousQueue to map this function over.
+     * @return A new SynchronousQueue with this function applied to each element.
+     */
+    static public <A, B> SynchronousQueue<B> mapJ(final F<A, B> f, final SynchronousQueue<A> as) {
+        final SynchronousQueue<B> bs = new SynchronousQueue<B>();
+        bs.addAll(iterableStream(as).map(f).toCollection());
+        return bs;
+    }
+
+
+    /**
+     * Maps this function over a PriorityBlockingQueue.
+     *
+     * @param as A PriorityBlockingQueue to map this function over.
+     * @return A new PriorityBlockingQueue with this function applied to each element.
+     */
+    static public <A, B> PriorityBlockingQueue<B> mapJ(final F<A, B> f, final PriorityBlockingQueue<A> as) {
+        return new PriorityBlockingQueue<B>(iterableStream(as).map(f).toCollection());
+    }
+
+    /**
+     * Maps this function over a LinkedBlockingQueue.
+     *
+     * @param as A LinkedBlockingQueue to map this function over.
+     * @return A new LinkedBlockingQueue with this function applied to each element.
+     */
+    static public <A, B> LinkedBlockingQueue<B> mapJ(final F<A, B> f, final LinkedBlockingQueue<A> as) {
+        return new LinkedBlockingQueue<B>(iterableStream(as).map(f).toCollection());
+    }
+
+    /**
+     * Maps this function over a CopyOnWriteArraySet.
+     *
+     * @param as A CopyOnWriteArraySet to map this function over.
+     * @return A new CopyOnWriteArraySet with this function applied to each element.
+     */
+    static public <A, B> CopyOnWriteArraySet<B> mapJ(final F<A, B> f, final CopyOnWriteArraySet<A> as) {
+        return new CopyOnWriteArraySet<B>(iterableStream(as).map(f).toCollection());
+    }
+
+    /**
+     * Maps this function over a CopyOnWriteArrayList.
+     *
+     * @param as A CopyOnWriteArrayList to map this function over.
+     * @return A new CopyOnWriteArrayList with this function applied to each element.
+     */
+    static public <A, B> CopyOnWriteArrayList<B> mapJ(final F<A, B> f, final CopyOnWriteArrayList<A> as) {
+        return new CopyOnWriteArrayList<B>(iterableStream(as).map(f).toCollection());
+    }
+
+    /**
+     * Maps this function over a ConcurrentLinkedQueue.
+     *
+     * @param as A ConcurrentLinkedQueue to map this function over.
+     * @return A new ConcurrentLinkedQueue with this function applied to each element.
+     */
+    static public <A, B> ConcurrentLinkedQueue<B> mapJ(final F<A, B> f, final ConcurrentLinkedQueue<A> as) {
+        return new ConcurrentLinkedQueue<B>(iterableStream(as).map(f).toCollection());
+    }
+
+    /**
+     * Maps this function over an ArrayBlockingQueue.
+     *
+     * @param as An ArrayBlockingQueue to map this function over.
+     * @return A new ArrayBlockingQueue with this function applied to each element.
+     */
+    static public <A, B> ArrayBlockingQueue<B> mapJ(final F<A, B> f, final ArrayBlockingQueue<A> as) {
+        final ArrayBlockingQueue<B> bs = new ArrayBlockingQueue<B>(as.size());
+        bs.addAll(iterableStream(as).map(f).toCollection());
+        return bs;
+    }
+
+
+    /**
+     * Maps this function over a TreeSet.
+     *
+     * @param as A TreeSet to map this function over.
+     * @return A new TreeSet with this function applied to each element.
+     */
+    static public <A, B> TreeSet<B> mapJ(final F<A, B> f, final TreeSet<A> as) {
+        return new TreeSet<B>(iterableStream(as).map(f).toCollection());
+    }
+
+    /**
+     * Maps this function over a PriorityQueue.
+     *
+     * @param as A PriorityQueue to map this function over.
+     * @return A new PriorityQueue with this function applied to each element.
+     */
+    static public <A, B> PriorityQueue<B> mapJ(final F<A, B> f, final PriorityQueue<A> as) {
+        return new PriorityQueue<B>(iterableStream(as).map(f).toCollection());
+    }
+
+    /**
+     * Maps this function over a LinkedList.
+     *
+     * @param as A LinkedList to map this function over.
+     * @return A new LinkedList with this function applied to each element.
+     */
+    static public <A, B> LinkedList<B> mapJ(final F<A, B> f, final LinkedList<A> as) {
+        return new LinkedList<B>(iterableStream(as).map(f).toCollection());
+    }
+
+    /**
+     * Maps this function over an ArrayList.
+     *
+     * @param as An ArrayList to map this function over.
+     * @return A new ArrayList with this function applied to each element.
+     */
+    static public <A, B> ArrayList<B> mapJ(final F<A, B> f, final ArrayList<A> as) {
+        return new ArrayList<B>(iterableStream(as).map(f).toCollection());
+    }
+
+    static public <A, B, C> F<A, C> map(F<A, B> target, F<B, C> f) {
+        return andThen(target, f);
+    }
+
+    static public <A, B, C> F<C, B> contramap(F<A, B> target, F<C, A> f) {
+        return andThen(f, target);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F2.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,38 @@
+package fj;
+
+import fj.control.parallel.Promise;
+import fj.data.Array;
+import fj.data.IterableW;
+import fj.data.List;
+import fj.data.NonEmptyList;
+import fj.data.Option;
+import fj.data.Set;
+import fj.data.Stream;
+import fj.data.Tree;
+import fj.data.TreeZipper;
+import fj.data.Zipper;
+
+import static fj.data.Tree.node;
+import static fj.P.p;
+import static fj.data.IterableW.wrap;
+import static fj.data.Set.iterableSet;
+import static fj.data.TreeZipper.treeZipper;
+import static fj.data.Zipper.zipper;
+
+/**
+ * A transformation function of arity-2 from <code>A</code> and <code>B</code> to <code>C</code>.
+ * This type can be represented using the Java 7 closure syntax.
+ *
+ * @version %build.number%
+ */
+public interface F2<A, B, C> {
+  /**
+   * Transform <code>A</code> and <code>B</code> to <code>C</code>.
+   *
+   * @param a The <code>A</code> to transform.
+   * @param b The <code>B</code> to transform.
+   * @return The result of the transformation.
+   */
+  public C f(A a, B b);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F2Functions.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,366 @@
+package fj;
+
+import fj.control.parallel.Promise;
+import fj.data.*;
+import fj.function.Try2;
+
+import static fj.P.p;
+import static fj.data.IterableW.wrap;
+import static fj.data.Set.iterableSet;
+import static fj.data.Tree.node;
+import static fj.data.TreeZipper.treeZipper;
+import static fj.data.Zipper.zipper;
+
+/**
+ * Created by MarkPerry on 6/04/2014.
+ */
+public class F2Functions {
+
+
+    /**
+     * Partial application.
+     *
+     * @param a The <code>A</code> to which to apply this function.
+     * @return The function partially applied to the given argument.
+     */
+    static public <A, B, C> F<B, C> f(final F2<A, B, C> f, final A a) {
+        return new F<B, C>() {
+            public C f(final B b) {
+                return f.f(a, b);
+            }
+        };
+    }
+
+    /**
+     * Curries this wrapped function to a wrapped function of arity-1 that returns another wrapped function.
+     *
+     * @return a wrapped function of arity-1 that returns another wrapped function.
+     */
+    static public <A, B, C> F<A, F<B, C>> curry(final F2<A, B, C> f) {
+        return new F<A, F<B, C>>() {
+            public F<B, C> f(final A a) {
+                return new F<B, C>() {
+                    public C f(final B b) {
+                        return f.f(a, b);
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Flips the arguments of this function.
+     *
+     * @return A new function with the arguments of this function flipped.
+     */
+    static public <A, B, C> F2<B, A, C> flip(final F2<A, B, C> f) {
+        return new F2<B, A, C>() {
+            public C f(final B b, final A a) {
+                return f.f(a, b);
+            }
+        };
+    }
+
+    /**
+     * Uncurries this function to a function on tuples.
+     *
+     * @return A new function that calls this function with the elements of a given tuple.
+     */
+    static public <A, B, C> F<P2<A, B>, C> tuple(final F2<A, B, C> f) {
+        return new F<P2<A, B>, C>() {
+            public C f(final P2<A, B> p) {
+                return f.f(p._1(), p._2());
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to a function on Arrays.
+     *
+     * @return This function promoted to transform Arrays.
+     */
+    static public <A, B, C> F2<Array<A>, Array<B>, Array<C>> arrayM(final F2<A, B, C> f) {
+        return new F2<Array<A>, Array<B>, Array<C>>() {
+            public Array<C> f(final Array<A> a, final Array<B> b) {
+                return a.bind(b, curry(f));
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to a function on Promises.
+     *
+     * @return This function promoted to transform Promises.
+     */
+    static public <A, B, C> F2<Promise<A>, Promise<B>, Promise<C>> promiseM(final F2<A, B, C> f) {
+        return new F2<Promise<A>, Promise<B>, Promise<C>>() {
+            public Promise<C> f(final Promise<A> a, final Promise<B> b) {
+                return a.bind(b, curry(f));
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to a function on Iterables.
+     *
+     * @return This function promoted to transform Iterables.
+     */
+    static public <A, B, C> F2<Iterable<A>, Iterable<B>, IterableW<C>> iterableM(final F2<A, B, C> f) {
+        return new F2<Iterable<A>, Iterable<B>, IterableW<C>>() {
+            public IterableW<C> f(final Iterable<A> a, final Iterable<B> b) {
+                return IterableW.liftM2(curry(f)).f(a).f(b);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to a function on Lists.
+     *
+     * @return This function promoted to transform Lists.
+     */
+    static public <A, B, C> F2<List<A>, List<B>, List<C>> listM(final F2<A, B, C> f) {
+        return new F2<List<A>, List<B>, List<C>>() {
+            public List<C> f(final List<A> a, final List<B> b) {
+                return List.liftM2(curry(f)).f(a).f(b);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to a function on non-empty lists.
+     *
+     * @return This function promoted to transform non-empty lists.
+     */
+    static public <A, B, C> F2<NonEmptyList<A>, NonEmptyList<B>, NonEmptyList<C>> nelM(final F2<A, B, C> f) {
+        return new F2<NonEmptyList<A>, NonEmptyList<B>, NonEmptyList<C>>() {
+            public NonEmptyList<C> f(final NonEmptyList<A> as, final NonEmptyList<B> bs) {
+                return NonEmptyList.fromList(as.toList().bind(bs.toList(), f)).some();
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to a function on Options.
+     *
+     * @return This function promoted to transform Options.
+     */
+    static public <A, B, C> F2<Option<A>, Option<B>, Option<C>> optionM(final F2<A, B, C> f) {
+        return new F2<Option<A>, Option<B>, Option<C>>() {
+            public Option<C> f(final Option<A> a, final Option<B> b) {
+                return Option.liftM2(curry(f)).f(a).f(b);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to a function on Sets.
+     *
+     * @param o An ordering for the result of the promoted function.
+     * @return This function promoted to transform Sets.
+     */
+    static public <A, B, C> F2<Set<A>, Set<B>, Set<C>> setM(final F2<A, B, C> f, final Ord<C> o) {
+        return new F2<Set<A>, Set<B>, Set<C>>() {
+            public Set<C> f(final Set<A> as, final Set<B> bs) {
+                Set<C> cs = Set.empty(o);
+                for (final A a : as)
+                    for (final B b : bs)
+                        cs = cs.insert(f.f(a, b));
+                return cs;
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to a function on Streams.
+     *
+     * @return This function promoted to transform Streams.
+     */
+    static public <A, B, C> F2<Stream<A>, Stream<B>, Stream<C>> streamM(final F2<A, B, C> f) {
+        return new F2<Stream<A>, Stream<B>, Stream<C>>() {
+            public Stream<C> f(final Stream<A> as, final Stream<B> bs) {
+                return as.bind(bs, f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to a function on Trees.
+     *
+     * @return This function promoted to transform Trees.
+     */
+    static public <A, B, C> F2<Tree<A>, Tree<B>, Tree<C>> treeM(final F2<A, B, C> f) {
+        return new F2<Tree<A>, Tree<B>, Tree<C>>() {
+            public Tree<C> f(final Tree<A> as, final Tree<B> bs) {
+                final F2<Tree<A>, Tree<B>, Tree<C>> self = this;
+                return node(f.f(as.root(), bs.root()), new P1<Stream<Tree<C>>>() {
+                    public Stream<Tree<C>> _1() {
+                        return streamM(self).f(as.subForest()._1(), bs.subForest()._1());
+                    }
+                });
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to zip two arrays, applying the function lock-step over both Arrays.
+     *
+     * @return A function that zips two arrays with this function.
+     */
+    static public <A, B, C> F2<Array<A>, Array<B>, Array<C>> zipArrayM(final F2<A, B, C> f) {
+        return new F2<Array<A>, Array<B>, Array<C>>() {
+            public Array<C> f(final Array<A> as, final Array<B> bs) {
+                return as.zipWith(bs, f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to zip two iterables, applying the function lock-step over both iterables.
+     *
+     * @return A function that zips two iterables with this function.
+     */
+    static public <A, B, C> F2<Iterable<A>, Iterable<B>, Iterable<C>> zipIterableM(final F2<A, B, C> f) {
+        return new F2<Iterable<A>, Iterable<B>, Iterable<C>>() {
+            public Iterable<C> f(final Iterable<A> as, final Iterable<B> bs) {
+                return wrap(as).zipWith(bs, f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to zip two lists, applying the function lock-step over both lists.
+     *
+     * @return A function that zips two lists with this function.
+     */
+    static public <A, B, C> F2<List<A>, List<B>, List<C>> zipListM(final F2<A, B, C> f) {
+        return new F2<List<A>, List<B>, List<C>>() {
+            public List<C> f(final List<A> as, final List<B> bs) {
+                return as.zipWith(bs, f);
+            }
+        };
+    }
+
+
+    /**
+     * Promotes this function to zip two streams, applying the function lock-step over both streams.
+     *
+     * @return A function that zips two streams with this function.
+     */
+    static public <A, B, C> F2<Stream<A>, Stream<B>, Stream<C>> zipStreamM(final F2<A, B, C> f) {
+        return new F2<Stream<A>, Stream<B>, Stream<C>>() {
+            public Stream<C> f(final Stream<A> as, final Stream<B> bs) {
+                return as.zipWith(bs, f);
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to zip two non-empty lists, applying the function lock-step over both lists.
+     *
+     * @return A function that zips two non-empty lists with this function.
+     */
+    static public <A, B, C> F2<NonEmptyList<A>, NonEmptyList<B>, NonEmptyList<C>> zipNelM(final F2<A, B, C> f) {
+        return new F2<NonEmptyList<A>, NonEmptyList<B>, NonEmptyList<C>>() {
+            public NonEmptyList<C> f(final NonEmptyList<A> as, final NonEmptyList<B> bs) {
+                return NonEmptyList.fromList(as.toList().zipWith(bs.toList(), f)).some();
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to zip two sets, applying the function lock-step over both sets.
+     *
+     * @param o An ordering for the resulting set.
+     * @return A function that zips two sets with this function.
+     */
+    static public <A, B, C> F2<Set<A>, Set<B>, Set<C>> zipSetM(final F2<A, B, C> f, final Ord<C> o) {
+        return new F2<Set<A>, Set<B>, Set<C>>() {
+            public Set<C> f(final Set<A> as, final Set<B> bs) {
+                return iterableSet(o, as.toStream().zipWith(bs.toStream(), f));
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to zip two trees, applying the function lock-step over both trees.
+     * The structure of the resulting tree is the structural intersection of the two trees.
+     *
+     * @return A function that zips two trees with this function.
+     */
+    static public <A, B, C> F2<Tree<A>, Tree<B>, Tree<C>> zipTreeM(final F2<A, B, C> f) {
+        return new F2<Tree<A>, Tree<B>, Tree<C>>() {
+            public Tree<C> f(final Tree<A> ta, final Tree<B> tb) {
+                final F2<Tree<A>, Tree<B>, Tree<C>> self = this;
+                return node(f.f(ta.root(), tb.root()), new P1<Stream<Tree<C>>>() {
+                    public Stream<Tree<C>> _1() {
+                        return zipStreamM(self).f(ta.subForest()._1(), tb.subForest()._1());
+                    }
+                });
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to zip two zippers, applying the function lock-step over both zippers in both directions.
+     * The structure of the resulting zipper is the structural intersection of the two zippers.
+     *
+     * @return A function that zips two zippers with this function.
+     */
+    static public <A, B, C> F2<Zipper<A>, Zipper<B>, Zipper<C>> zipZipperM(final F2<A, B, C> f) {
+        return new F2<Zipper<A>, Zipper<B>, Zipper<C>>() {
+            @SuppressWarnings({"unchecked"})
+            public Zipper<C> f(final Zipper<A> ta, final Zipper<B> tb) {
+                final F2<Stream<A>, Stream<B>, Stream<C>> sf = zipStreamM(f);
+                return zipper(sf.f(ta.lefts(), tb.lefts()), f.f(ta.focus(), tb.focus()), sf.f(ta.rights(), tb.rights()));
+            }
+        };
+    }
+
+    /**
+     * Promotes this function to zip two TreeZippers, applying the function lock-step over both zippers in all directions.
+     * The structure of the resulting TreeZipper is the structural intersection of the two TreeZippers.
+     *
+     * @return A function that zips two TreeZippers with this function.
+     */
+    static public <A, B, C> F2<TreeZipper<A>, TreeZipper<B>, TreeZipper<C>> zipTreeZipperM(final F2<A, B, C> f) {
+        return new F2<TreeZipper<A>, TreeZipper<B>, TreeZipper<C>>() {
+            @SuppressWarnings({"unchecked"})
+            public TreeZipper<C> f(final TreeZipper<A> ta, final TreeZipper<B> tb) {
+                final F2<Stream<Tree<A>>, Stream<Tree<B>>, Stream<Tree<C>>> sf = zipStreamM(treeM(f));
+                final
+                F2<Stream<P3<Stream<Tree<A>>, A, Stream<Tree<A>>>>,
+                        Stream<P3<Stream<Tree<B>>, B, Stream<Tree<B>>>>,
+                        Stream<P3<Stream<Tree<C>>, C, Stream<Tree<C>>>>>
+                        pf =
+                        zipStreamM(new F2<P3<Stream<Tree<A>>, A, Stream<Tree<A>>>,
+                                P3<Stream<Tree<B>>, B, Stream<Tree<B>>>,
+                                P3<Stream<Tree<C>>, C, Stream<Tree<C>>>>() {
+                            public P3<Stream<Tree<C>>, C, Stream<Tree<C>>> f(final P3<Stream<Tree<A>>, A, Stream<Tree<A>>> pa,
+                                                                             final P3<Stream<Tree<B>>, B, Stream<Tree<B>>> pb) {
+                                return p(zipStreamM(treeM(f)).f(pa._1(), pb._1()), f.f(pa._2(), pb._2()),
+                                        zipStreamM(treeM(f)).f(pa._3(), pb._3()));
+                            }
+                        });
+                return treeZipper(treeM(f).f(ta.p()._1(), tb.p()._1()), sf.f(ta.lefts(), tb.lefts()),
+                        sf.f(ta.rights(), tb.rights()), pf.f(ta.p()._4(), tb.p()._4()));
+            }
+        };
+    }
+
+    static public <A, B, C, Z> F2<Z, B, C> contramapFirst(F2<A, B, C> target, F<Z, A> f) {
+        return (z, b) -> target.f(f.f(z), b);
+    }
+
+    static public <A, B, C, Z> F2<A, Z, C> contramapSecond(F2<A, B, C> target, F<Z, B> f) {
+        return (a, z) -> target.f(a, f.f(z));
+    }
+
+    static public <A, B, C, X, Y> F2<X, Y, C> contramap(F2<A, B, C> target, F<X, A> f, F<Y, B> g) {
+        return contramapSecond(contramapFirst(target, f), g);
+    }
+
+    static public <A, B, C, Z> F2<A, B, Z> map(F2<A, B, C> target, F<C, Z> f) {
+        return (a, b) -> f.f(target.f(a, b));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F3.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,19 @@
+package fj;
+
+/**
+ * A transformation function of arity-3 from <code>A</code>, <code>B</code> and <code>C</code> to
+ * <code>D</code>. This type can be represented using the Java 7 closure syntax.
+ *
+ * @version %build.number%
+ */
+public interface F3<A, B, C, D> {
+  /**
+   * Transform <code>A</code>, <code>B</code> and <code>C</code> to <code>D</code>.
+   *
+   * @param a The <code>A</code> to transform.
+   * @param b The <code>B</code> to transform.
+   * @param c The <code>C</code> to transform.
+   * @return The result of the transformation.
+   */
+  public D f(A a, B b, C c);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F3Functions.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,25 @@
+package fj;
+
+import fj.data.Validation;
+import fj.function.Try3;
+
+import static fj.data.Validation.fail;
+import static fj.data.Validation.success;
+
+/**
+ * Created by MarkPerry on 6/04/2014.
+ */
+public class F3Functions {
+
+
+    /**
+     * Partial application.
+     *
+     * @param a The <code>A</code> to which to apply this function.
+     * @return The function partially applied to the given argument.
+     */
+    static public <A, B, C, D> F2<B, C, D> f(final F3<A, B, C, D> f, final A a) {
+        return (b, c) -> f.f(a, b, c);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F4.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,20 @@
+package fj;
+
+/**
+ * A transformation function of arity-4 from <code>A</code>, <code>B</code>, <code>C</code> and
+ * <code>D</code> to <code>E</code>. This type can be represented using the Java 7 closure syntax.
+ *
+ * @version %build.number%
+ */
+public interface F4<A, B, C, D, E> {
+  /**
+   * Transform <code>A</code>, <code>B</code>, <code>C</code> and <code>D</code> to <code>E</code>.
+   *
+   * @param a The <code>A</code> to transform.
+   * @param b The <code>B</code> to transform.
+   * @param c The <code>C</code> to transform.
+   * @param d The <code>D</code> to transform.
+   * @return The result of the transformation.
+   */
+  public E f(A a, B b, C c, D d);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F4Functions.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,21 @@
+package fj;
+
+import fj.data.Validation;
+import fj.function.Try4;
+
+/**
+ * Created by MarkPerry on 6/04/2014.
+ */
+public class F4Functions {
+
+    /**
+     * Partial application.
+     *
+     * @param a The <code>A</code> to which to apply this function.
+     * @return The function partially applied to the given argument.
+     */
+    static public <A, B, C, D, E> F3<B, C, D, E> f(final F4<A, B, C, D, E> f, final A a) {
+        return (b, c, d) -> f.f(a, b, c, d);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F5.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,23 @@
+package fj;
+
+/**
+ * A transformation function of arity-5 from <code>A</code>, <code>B</code>, <code>C</code>,
+ * <code>D</code> and <code>E</code> to <code>F$</code>. This type can be represented using the Java
+ * 7 closure syntax.
+ *
+ * @version %build.number%
+ */
+public interface F5<A, B, C, D, E, F$> {
+  /**
+   * Transform <code>A</code>, <code>B</code>, <code>C</code>, <code>D</code> and <code>E</code> to
+   * <code>F$</code>.
+   *
+   * @param a The <code>A</code> to transform.
+   * @param b The <code>B</code> to transform.
+   * @param c The <code>C</code> to transform.
+   * @param d The <code>D</code> to transform.
+   * @param e The <code>E</code> to transform.
+   * @return The result of the transformation.
+   */
+  public F$ f(A a, B b, C c, D d, E e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F5Functions.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,21 @@
+package fj;
+
+import fj.data.Validation;
+import fj.function.Try5;
+
+/**
+ * Created by MarkPerry on 6/04/2014.
+ */
+public class F5Functions {
+
+	/**
+	 * Partial application.
+	 *
+	 * @param a The <code>A</code> to which to apply this function.
+	 * @return The function partially applied to the given argument.
+	 */
+	static public <A, B, C, D, E, F$> F4<B, C, D, E, F$> f(final F5<A, B, C, D, E, F$> f, final A a) {
+		return (b, c, d, e) -> f.f(a, b, c, d, e);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F6.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,24 @@
+package fj;
+
+/**
+ * A transformation function of arity-6 from <code>A</code>, <code>B</code>, <code>C</code>,
+ * <code>D</code>, <code>E</code> and <code>F$</code> to <code>G</code>. This type can be
+ * represented using the Java 7 closure syntax.
+ *
+ * @version %build.number%
+ */
+public interface F6<A, B, C, D, E, F$, G> {
+  /**
+   * Transform <code>A</code>, <code>B</code>, <code>C</code>, <code>D</code>, <code>E</code> and
+   * <code>F$</code> to <code>G</code>.
+   *
+   * @param a The <code>A</code> to transform.
+   * @param b The <code>B</code> to transform.
+   * @param c The <code>C</code> to transform.
+   * @param d The <code>D</code> to transform.
+   * @param e The <code>E</code> to transform.
+   * @param f The <code>F$</code> to transform.
+   * @return The result of the transformation.
+   */
+  public G f(A a, B b, C c, D d, E e, F$ f);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F6Functions.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,22 @@
+package fj;
+
+import fj.data.Validation;
+import fj.function.Try6;
+
+/**
+ * Created by MarkPerry on 6/04/2014.
+ */
+public class F6Functions {
+
+	/**
+	 * Partial application.
+	 *
+	 * @param a The <code>A</code> to which to apply this function.
+	 * @return The function partially applied to the given argument.
+	 */
+	static public <A, B, C, D, E, F$, G> F5<B, C, D, E, F$, G> f(final F6<A, B, C, D, E, F$, G> func, final A a) {
+		return (b, c, d, e, f) -> func.f(a, b, c, d, e, f);
+	}
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F7.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,25 @@
+package fj;
+
+/**
+ * A transformation function of arity-7 from <code>A</code>, <code>B</code>, <code>C</code>,
+ * <code>D</code>, <code>E</code>, <code>F$</code> and <code>G</code> to <code>H</code>. This type
+ * can be represented using the Java 7 closure syntax.
+ *
+ * @version %build.number%
+ */
+public interface F7<A, B, C, D, E, F$, G, H> {
+  /**
+   * Transform <code>A</code>, <code>B</code>, <code>C</code>, <code>D</code>, <code>E</code>,
+   * <code>F$</code> and <code>G</code> to <code>H</code>.
+   *
+   * @param a The <code>A</code> to transform.
+   * @param b The <code>B</code> to transform.
+   * @param c The <code>C</code> to transform.
+   * @param d The <code>D</code> to transform.
+   * @param e The <code>E</code> to transform.
+   * @param f The <code>F$</code> to transform.
+   * @param g The <code>G</code> to transform.
+   * @return The result of the transformation.
+   */
+  public H f(A a, B b, C c, D d, E e, F$ f, G g);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F7Functions.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,22 @@
+package fj;
+
+import fj.data.Validation;
+import fj.function.Try7;
+
+/**
+ * Created by MarkPerry on 6/04/2014.
+ */
+public class F7Functions {
+
+	/**
+	 * Partial application.
+	 *
+	 * @param a The <code>A</code> to which to apply this function.
+	 * @return The function partially applied to the given argument.
+	 */
+	static public <A, B, C, D, E, F$, G, H> F6<B, C, D, E, F$, G, H> f(final F7<A, B, C, D, E, F$, G, H> func, final A a) {
+		return (b, c, d, e, f, g) -> func.f(a, b, c, d, e, f, g);
+	}
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F8.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,26 @@
+package fj;
+
+/**
+ * A transformation function of arity-8 from <code>A</code>, <code>B</code>, <code>C</code>,
+ * <code>D</code>, <code>E</code>, <code>F$</code>, <code>G</code> and <code>H</code> to
+ * <code>I</code>. This type can be represented using the Java 7 closure syntax.
+ *
+ * @version %build.number%
+ */
+public interface F8<A, B, C, D, E, F$, G, H, I> {
+  /**
+   * Transform <code>A</code>, <code>B</code>, <code>C</code>, <code>D</code>, <code>E</code>,
+   * <code>F$</code>, <code>G</code> and <code>H</code> to <code>I</code>.
+   *
+   * @param a The <code>A</code> to transform.
+   * @param b The <code>B</code> to transform.
+   * @param c The <code>C</code> to transform.
+   * @param d The <code>D</code> to transform.
+   * @param e The <code>E</code> to transform.
+   * @param f The <code>F$</code> to transform.
+   * @param g The <code>G</code> to transform.
+   * @param h The <code>H</code> to transform.
+   * @return The result of the transformation.
+   */
+  public I f(A a, B b, C c, D d, E e, F$ f, G g, H h);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/F8Functions.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,21 @@
+package fj;
+
+import fj.data.Validation;
+import fj.function.Try8;
+
+/**
+ * Created by MarkPerry on 6/04/2014.
+ */
+public class F8Functions {
+
+	/**
+	 * Partial application.
+	 *
+	 * @param a The <code>A</code> to which to apply this function.
+	 * @return The function partially applied to the given argument.
+	 */
+	static public <A, B, C, D, E, F$, G, H, I> F7<B, C, D, E, F$, G, H, I> f(final F8<A, B, C, D, E, F$, G, H, I> func, final A a) {
+		return (b, c, d, e, f, g, h) -> func.f(a, b, c, d, e, f, g, h);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/Function.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,1259 @@
+package fj;
+
+import fj.data.Option;
+
+/**
+ * Transformations on functions.
+ *
+ * @version %build.number%
+ */
+public final class Function {
+  private Function() {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * Function application with the arguments flipped.
+   *
+   * @param a The value to apply the function to.
+   * @return A function that is partially-applied to the given value.
+   */
+  public static <A, B> F<F<A, B>, B> apply(final A a) {
+    return new F<F<A, B>, B>() {
+      public B f(final F<A, B> k) {
+        return k.f(a);
+      }
+    };
+  }
+
+  /**
+   * Function composition.
+   *
+   * @return A function that composes two functions to produce a new function.
+   */
+  public static <A, B, C> F<F<B, C>, F<F<A, B>, F<A, C>>> compose() {
+    return new F<F<B, C>, F<F<A, B>, F<A, C>>>() {
+      public F<F<A, B>, F<A, C>> f(final F<B, C> f) {
+        return new F<F<A, B>, F<A, C>>() {
+          public F<A, C> f(final F<A, B> g) {
+            return compose(f, g);
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Function composition.
+   *
+   * @param f A function to compose with another.
+   * @param g A function to compose with another.
+   * @return A function that is the composition of the given arguments.
+   */
+  public static <A, B, C> F<A, C> compose(final F<B, C> f, final F<A, B> g) {
+    return new F<A, C>() {
+      public C f(final A a) {
+        return f.f(g.f(a));
+      }
+    };
+  }
+
+  /**
+   * Function composition.
+   *
+   * @param f A function to compose with another.
+   * @param g A function to compose with another.
+   * @return A function that is the composition of the given arguments.
+   */
+  public static <A, B, C, D> F<A, F<B, D>> compose2(final F<C, D> f, final F<A, F<B, C>> g) {
+    return new F<A, F<B, D>>() {
+      public F<B, D> f(final A a) {
+        return new F<B, D>() {
+          public D f(final B b) {
+            return f.f(g.f(a).f(b));
+          }
+        };
+      }
+    };
+  }
+
+
+  /**
+   * Function composition flipped.
+   *
+   * @return A function that composes two functions to produce a new function.
+   */
+  public static <A, B, C> F<F<A, B>, F<F<B, C>, F<A, C>>> andThen() {
+    return new F<F<A, B>, F<F<B, C>, F<A, C>>>() {
+      public F<F<B, C>, F<A, C>> f(final F<A, B> g) {
+        return new F<F<B, C>, F<A, C>>() {
+          public F<A, C> f(final F<B, C> f) {
+            return Function.andThen(g, f);
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Function composition flipped.
+   *
+   * @param g A function to compose with another.
+   * @param f A function to compose with another.
+   * @return A function that is the composition of the given arguments.
+   */
+  public static <A, B, C> F<A, C> andThen(final F<A, B> g, final F<B, C> f) {
+    return new F<A, C>() {
+      public C f(final A a) {
+        return f.f(g.f(a));
+      }
+    };
+  }
+
+  /**
+   * The identity transformation.
+   *
+   * @return The identity transformation.
+   */
+  public static <A> F<A, A> identity() {
+    return new F<A, A>() {
+      public A f(final A a) {
+        return a;
+      }
+    };
+  }
+
+  /**
+   * Returns a function that given an argument, returns a function that ignores its argument.
+   *
+   * @return A function that given an argument, returns a function that ignores its argument.
+   */
+  public static <A, B> F<B, F<A, B>> constant() {
+    return new F<B, F<A, B>>() {
+      public F<A, B> f(final B b) {
+        return constant(b);
+      }
+    };
+  }
+
+  /**
+   * Returns a function that ignores its argument to constantly produce the given value.
+   *
+   * @param b The value to return when the returned function is applied.
+   * @return A function that ignores its argument to constantly produce the given value.
+   */
+  public static <A, B> F<A, B> constant(final B b) {
+    return new F<A, B>() {
+      public B f(final A a) {
+        return b;
+      }
+    };
+  }
+
+  /**
+   * Simultaneously covaries and contravaries a function.
+   *
+   * @param f The function to vary.
+   * @return A co- and contravariant function that invokes f on its argument.
+   */
+  public static <A, B> F<A, B> vary(final F<? super A, ? extends B> f) {
+    return new F<A, B>() {
+      public B f(final A a) {
+        return f.f(a);
+      }
+    };
+  }
+
+  /**
+   * Simultaneously covaries and contravaries a function.
+   *
+   * @return A function that varies and covaries a function.
+   */
+  public static <C, A extends C, B, D extends B> F<F<C, D>, F<A, B>> vary() {
+    return new F<F<C, D>, F<A, B>>() {
+      public F<A, B> f(final F<C, D> f) {
+        return Function.<A, B>vary(f);
+      }
+    };
+  }
+
+  /**
+   * Function argument flipping.
+   *
+   * @return A function that takes a function and flips its arguments.
+   */
+  public static <A, B, C> F<F<A, F<B, C>>, F<B, F<A, C>>> flip() {
+    return new F<F<A, F<B, C>>, F<B, F<A, C>>>() {
+      public F<B, F<A, C>> f(final F<A, F<B, C>> f) {
+        return flip(f);
+      }
+    };
+  }
+
+  /**
+   * Function argument flipping.
+   *
+   * @param f The function to flip.
+   * @return The given function flipped.
+   */
+  public static <A, B, C> F<B, F<A, C>> flip(final F<A, F<B, C>> f) {
+    return new F<B, F<A, C>>() {
+      public F<A, C> f(final B b) {
+        return new F<A, C>() {
+          public C f(final A a) {
+            return f.f(a).f(b);
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Function argument flipping.
+   *
+   * @param f The function to flip.
+   * @return The given function flipped.
+   */
+  public static <A, B, C> F2<B, A, C> flip(final F2<A, B, C> f) {
+    return new F2<B, A, C>() {
+      public C f(final B b, final A a) {
+        return f.f(a, b);
+      }
+    };
+  }
+
+  /**
+   * Function argument flipping.
+   *
+   * @return A function that flips the arguments of a given function.
+   */
+  public static <A, B, C> F<F2<A, B, C>, F2<B, A, C>> flip2() {
+    return new F<F2<A, B, C>, F2<B, A, C>>() {
+      public F2<B, A, C> f(final F2<A, B, C> f) {
+        return flip(f);
+      }
+    };
+  }
+
+  /**
+   * Return a function that inspects the argument of the given function for a <code>null</code> value and if so, does
+   * not apply the value, instead returning an empty optional value.
+   *
+   * @param f The function to check for a <code>null</code> argument.
+   * @return A function that inspects the argument of the given function for a <code>null</code> value and if so, does
+   * not apply the value, instead returning an empty optional value.
+   */
+  public static <A, B> F<A, Option<B>> nullable(final F<A, B> f) {
+    return new F<A, Option<B>>() {
+      public Option<B> f(final A a) {
+        return a == null ? Option.<B>none() : Option.some(f.f(a));
+      }
+    };
+  }
+
+  /**
+   * Curry a function of arity-2.
+   *
+   * @param f The function to curry.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C> F<A, F<B, C>> curry(final F2<A, B, C> f) {
+    return new F<A, F<B, C>>() {
+      public F<B, C> f(final A a) {
+        return new F<B, C>() {
+          public C f(final B b) {
+            return f.f(a, b);
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Curry a function of arity-2.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C> F<B, C> curry(final F2<A, B, C> f, final A a) {
+    return curry(f).f(a);
+  }
+
+  /**
+   * Uncurry a function of arity-2.
+   *
+   * @return An uncurried function.
+   */
+  public static <A, B, C> F<F<A, F<B, C>>, F2<A, B, C>> uncurryF2() {
+    return new F<F<A, F<B, C>>, F2<A, B, C>>() {
+      public F2<A, B, C> f(final F<A, F<B, C>> f) {
+        return uncurryF2(f);
+      }
+    };
+  }
+
+  /**
+   * Uncurry a function of arity-2.
+   *
+   * @param f The function to uncurry.
+   * @return An uncurried function.
+   */
+  public static <A, B, C> F2<A, B, C> uncurryF2(final F<A, F<B, C>> f) {
+    return new F2<A, B, C>() {
+      public C f(final A a, final B b) {
+        return f.f(a).f(b);
+      }
+    };
+  }
+
+  /**
+   * Curry a function of arity-3.
+   *
+   * @param f The function to curry.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D> F<A, F<B, F<C, D>>> curry(final F3<A, B, C, D> f) {
+    return new F<A, F<B, F<C, D>>>() {
+      public F<B, F<C, D>> f(final A a) {
+        return new F<B, F<C, D>>() {
+          public F<C, D> f(final B b) {
+            return new F<C, D>() {
+              public D f(final C c) {
+                return f.f(a, b, c);
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Curry a function of arity-3.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D> F<B, F<C, D>> curry(final F3<A, B, C, D> f, final A a) {
+    return curry(f).f(a);
+  }
+
+  /**
+   * Curry a function of arity-3.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D> F<C, D> curry(final F3<A, B, C, D> f, final A a, final B b) {
+    return curry(f, a).f(b);
+  }
+
+  /**
+   * Uncurry a function of arity-3.
+   *
+   * @return An uncurried function.
+   */
+  public static <A, B, C, D> F<F<A, F<B, F<C, D>>>, F3<A, B, C, D>> uncurryF3() {
+    return new F<F<A, F<B, F<C, D>>>, F3<A, B, C, D>>() {
+      public F3<A, B, C, D> f(final F<A, F<B, F<C, D>>> f) {
+        return uncurryF3(f);
+      }
+    };
+  }
+
+  /**
+   * Uncurry a function of arity-3.
+   *
+   * @param f The function to uncurry.
+   * @return An uncurried function.
+   */
+  public static <A, B, C, D> F3<A, B, C, D> uncurryF3(final F<A, F<B, F<C, D>>> f) {
+    return new F3<A, B, C, D>() {
+      public D f(final A a, final B b, final C c) {
+        return f.f(a).f(b).f(c);
+      }
+    };
+  }
+
+  /**
+   * Curry a function of arity-4.
+   *
+   * @param f The function to curry.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E> F<A, F<B, F<C, F<D, E>>>> curry(final F4<A, B, C, D, E> f) {
+    return new F<A, F<B, F<C, F<D, E>>>>() {
+      public F<B, F<C, F<D, E>>> f(final A a) {
+        return new F<B, F<C, F<D, E>>>() {
+          public F<C, F<D, E>> f(final B b) {
+            return new F<C, F<D, E>>() {
+              public F<D, E> f(final C c) {
+                return new F<D, E>() {
+                  public E f(final D d) {
+                    return f.f(a, b, c, d);
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Curry a function of arity-4.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E> F<B, F<C, F<D, E>>> curry(final F4<A, B, C, D, E> f, final A a) {
+    return curry(f).f(a);
+  }
+
+  /**
+   * Curry a function of arity-4.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E> F<C, F<D, E>> curry(final F4<A, B, C, D, E> f, final A a, final B b) {
+    return curry(f).f(a).f(b);
+  }
+
+  /**
+   * Curry a function of arity-4.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @param c An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E> F<D, E> curry(final F4<A, B, C, D, E> f, final A a, final B b, final C c) {
+    return curry(f).f(a).f(b).f(c);
+  }
+
+  /**
+   * Uncurry a function of arity-4.
+   *
+   * @return An uncurried function.
+   */
+  public static <A, B, C, D, E> F<F<A, F<B, F<C, F<D, E>>>>, F4<A, B, C, D, E>> uncurryF4() {
+    return new F<F<A, F<B, F<C, F<D, E>>>>, F4<A, B, C, D, E>>() {
+      public F4<A, B, C, D, E> f(final F<A, F<B, F<C, F<D, E>>>> f) {
+        return uncurryF4(f);
+      }
+    };
+  }
+
+  /**
+   * Uncurry a function of arity-4.
+   *
+   * @param f The function to uncurry.
+   * @return An uncurried function.
+   */
+  public static <A, B, C, D, E> F4<A, B, C, D, E> uncurryF4(final F<A, F<B, F<C, F<D, E>>>> f) {
+    return new F4<A, B, C, D, E>() {
+      public E f(final A a, final B b, final C c, final D d) {
+        return f.f(a).f(b).f(c).f(d);
+      }
+    };
+  }
+
+  /**
+   * Curry a function of arity-5.
+   *
+   * @param f The function to curry.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$> F<A, F<B, F<C, F<D, F<E, F$>>>>> curry(final F5<A, B, C, D, E, F$> f) {
+    return new F<A, F<B, F<C, F<D, F<E, F$>>>>>() {
+      public F<B, F<C, F<D, F<E, F$>>>> f(final A a) {
+        return new F<B, F<C, F<D, F<E, F$>>>>() {
+          public F<C, F<D, F<E, F$>>> f(final B b) {
+            return new F<C, F<D, F<E, F$>>>() {
+              public F<D, F<E, F$>> f(final C c) {
+                return new F<D, F<E, F$>>() {
+                  public F<E, F$> f(final D d) {
+                    return new F<E, F$>() {
+                      public F$ f(final E e) {
+                        return f.f(a, b, c, d, e);
+                      }
+                    };
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Curry a function of arity-5.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$> F<B, F<C, F<D, F<E, F$>>>> curry(final F5<A, B, C, D, E, F$> f, final A a) {
+    return curry(f).f(a);
+  }
+
+  /**
+   * Curry a function of arity-5.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$> F<C, F<D, F<E, F$>>> curry(final F5<A, B, C, D, E, F$> f, final A a, final B b) {
+    return curry(f).f(a).f(b);
+  }
+
+  /**
+   * Curry a function of arity-5.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @param c An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$> F<D, F<E, F$>> curry(final F5<A, B, C, D, E, F$> f, final A a, final B b,
+                                                         final C c) {
+    return curry(f).f(a).f(b).f(c);
+  }
+
+  /**
+   * Curry a function of arity-5.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @param c An argument to the curried function.
+   * @param d An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$> F<E, F$> curry(final F5<A, B, C, D, E, F$> f, final A a, final B b, final C c,
+                                                   final D d) {
+    return curry(f).f(a).f(b).f(c).f(d);
+  }
+
+  /**
+   * Uncurry a function of arity-5.
+   *
+   * @return An uncurried function.
+   */
+  public static <A, B, C, D, E, F$> F<F<A, F<B, F<C, F<D, F<E, F$>>>>>, F5<A, B, C, D, E, F$>> uncurryF5() {
+    return new F<F<A, F<B, F<C, F<D, F<E, F$>>>>>, F5<A, B, C, D, E, F$>>() {
+      public F5<A, B, C, D, E, F$> f(final F<A, F<B, F<C, F<D, F<E, F$>>>>> f) {
+        return uncurryF5(f);
+      }
+    };
+  }
+
+  /**
+   * Uncurry a function of arity-6.
+   *
+   * @param f The function to uncurry.
+   * @return An uncurried function.
+   */
+  public static <A, B, C, D, E, F$> F5<A, B, C, D, E, F$> uncurryF5(final F<A, F<B, F<C, F<D, F<E, F$>>>>> f) {
+    return new F5<A, B, C, D, E, F$>() {
+      public F$ f(final A a, final B b, final C c, final D d, final E e) {
+        return f.f(a).f(b).f(c).f(d).f(e);
+      }
+    };
+  }
+
+  /**
+   * Curry a function of arity-6.
+   *
+   * @param f The function to curry.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G> F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>> curry(final F6<A, B, C, D, E, F$, G> f) {
+    return new F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>>() {
+      public F<B, F<C, F<D, F<E, F<F$, G>>>>> f(final A a) {
+        return new F<B, F<C, F<D, F<E, F<F$, G>>>>>() {
+          public F<C, F<D, F<E, F<F$, G>>>> f(final B b) {
+            return new F<C, F<D, F<E, F<F$, G>>>>() {
+              public F<D, F<E, F<F$, G>>> f(final C c) {
+                return new F<D, F<E, F<F$, G>>>() {
+                  public F<E, F<F$, G>> f(final D d) {
+                    return new F<E, F<F$, G>>() {
+                      public F<F$, G> f(final E e) {
+                        return new F<F$, G>() {
+                          public G f(final F$ f$) {
+                            return f.f(a, b, c, d, e, f$);
+                          }
+                        };
+                      }
+                    };
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Uncurry a function of arity-6.
+   *
+   * @return An uncurried function.
+   */
+  public static <A, B, C, D, E, F$, G> F<F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>>, F6<A, B, C, D, E, F$, G>> uncurryF6() {
+    return new F<F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>>, F6<A, B, C, D, E, F$, G>>() {
+      public F6<A, B, C, D, E, F$, G> f(final F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>> f) {
+        return uncurryF6(f);
+      }
+    };
+  }
+
+  /**
+   * Uncurry a function of arity-6.
+   *
+   * @param f The function to uncurry.
+   * @return An uncurried function.
+   */
+  public static <A, B, C, D, E, F$, G> F6<A, B, C, D, E, F$, G> uncurryF6(
+      final F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>> f) {
+    return new F6<A, B, C, D, E, F$, G>() {
+      public G f(final A a, final B b, final C c, final D d, final E e, final F$ f$) {
+        return f.f(a).f(b).f(c).f(d).f(e).f(f$);
+      }
+    };
+  }
+
+  /**
+   * Curry a function of arity-7.
+   *
+   * @param f The function to curry.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H> F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>> curry(
+      final F7<A, B, C, D, E, F$, G, H> f) {
+    return new F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>>() {
+      public F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>> f(final A a) {
+        return new F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>() {
+          public F<C, F<D, F<E, F<F$, F<G, H>>>>> f(final B b) {
+            return new F<C, F<D, F<E, F<F$, F<G, H>>>>>() {
+              public F<D, F<E, F<F$, F<G, H>>>> f(final C c) {
+                return new F<D, F<E, F<F$, F<G, H>>>>() {
+                  public F<E, F<F$, F<G, H>>> f(final D d) {
+                    return new F<E, F<F$, F<G, H>>>() {
+                      public F<F$, F<G, H>> f(final E e) {
+                        return new F<F$, F<G, H>>() {
+                          public F<G, H> f(final F$ f$) {
+                            return new F<G, H>() {
+                              public H f(final G g) {
+                                return f.f(a, b, c, d, e, f$, g);
+                              }
+                            };
+                          }
+                        };
+                      }
+                    };
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Curry a function of arity-7.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H> F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>> curry(
+      final F7<A, B, C, D, E, F$, G, H> f, final A a) {
+    return curry(f).f(a);
+  }
+
+  /**
+   * Curry a function of arity-7.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H> F<C, F<D, F<E, F<F$, F<G, H>>>>> curry(final F7<A, B, C, D, E, F$, G, H> f,
+                                                                                 final A a, final B b) {
+    return curry(f).f(a).f(b);
+  }
+
+  /**
+   * Curry a function of arity-7.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @param c An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H> F<D, F<E, F<F$, F<G, H>>>> curry(final F7<A, B, C, D, E, F$, G, H> f,
+                                                                           final A a, final B b, final C c) {
+    return curry(f).f(a).f(b).f(c);
+  }
+
+  /**
+   * Curry a function of arity-7.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @param c An argument to the curried function.
+   * @param d An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H> F<E, F<F$, F<G, H>>> curry(final F7<A, B, C, D, E, F$, G, H> f, final A a,
+                                                                     final B b, final C c, final D d) {
+    return curry(f).f(a).f(b).f(c).f(d);
+  }
+
+  /**
+   * Curry a function of arity-7.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @param c An argument to the curried function.
+   * @param d An argument to the curried function.
+   * @param e An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H> F<F$, F<G, H>> curry(final F7<A, B, C, D, E, F$, G, H> f, final A a,
+                                                               final B b, final C c, final D d, final E e) {
+    return curry(f).f(a).f(b).f(c).f(d).f(e);
+  }
+
+  /**
+   * Curry a function of arity-7.
+   *
+   * @param f  The function to curry.
+   * @param a  An argument to the curried function.
+   * @param b  An argument to the curried function.
+   * @param c  An argument to the curried function.
+   * @param d  An argument to the curried function.
+   * @param e  An argument to the curried function.
+   * @param f$ An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H> F<G, H> curry(final F7<A, B, C, D, E, F$, G, H> f, final A a, final B b,
+                                                        final C c, final D d, final E e, final F$ f$) {
+    return curry(f).f(a).f(b).f(c).f(d).f(e).f(f$);
+  }
+
+  /**
+   * Uncurry a function of arity-7.
+   *
+   * @return An uncurried function.
+   */
+  public static <A, B, C, D, E, F$, G, H> F<F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>>, F7<A, B, C, D, E, F$, G, H>> uncurryF7() {
+    return new F<F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>>, F7<A, B, C, D, E, F$, G, H>>() {
+      public F7<A, B, C, D, E, F$, G, H> f(final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>> f) {
+        return uncurryF7(f);
+      }
+    };
+  }
+
+  /**
+   * Uncurry a function of arity-7.
+   *
+   * @param f The function to uncurry.
+   * @return An uncurried function.
+   */
+  public static <A, B, C, D, E, F$, G, H> F7<A, B, C, D, E, F$, G, H> uncurryF7(
+      final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>> f) {
+    return new F7<A, B, C, D, E, F$, G, H>() {
+      public H f(final A a, final B b, final C c, final D d, final E e, final F$ f$, final G g) {
+        return f.f(a).f(b).f(c).f(d).f(e).f(f$).f(g);
+      }
+    };
+  }
+
+  /**
+   * Curry a function of arity-8.
+   *
+   * @param f The function to curry.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H, I> F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>> curry(
+      final F8<A, B, C, D, E, F$, G, H, I> f) {
+    return new F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>>() {
+      public F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>> f(final A a) {
+        return new F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>() {
+          public F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>> f(final B b) {
+            return new F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>() {
+              public F<D, F<E, F<F$, F<G, F<H, I>>>>> f(final C c) {
+                return new F<D, F<E, F<F$, F<G, F<H, I>>>>>() {
+                  public F<E, F<F$, F<G, F<H, I>>>> f(final D d) {
+                    return new F<E, F<F$, F<G, F<H, I>>>>() {
+                      public F<F$, F<G, F<H, I>>> f(final E e) {
+                        return new F<F$, F<G, F<H, I>>>() {
+                          public F<G, F<H, I>> f(final F$ f$) {
+                            return new F<G, F<H, I>>() {
+                              public F<H, I> f(final G g) {
+                                return new F<H, I>() {
+                                  public I f(final H h) {
+                                    return f.f(a, b, c, d, e, f$, g, h);
+                                  }
+                                };
+                              }
+                            };
+                          }
+                        };
+                      }
+                    };
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Curry a function of arity-8.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H, I> F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>> curry(
+      final F8<A, B, C, D, E, F$, G, H, I> f, final A a) {
+    return curry(f).f(a);
+  }
+
+  /**
+   * Curry a function of arity-8.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H, I> F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>> curry(
+      final F8<A, B, C, D, E, F$, G, H, I> f, final A a, final B b) {
+    return curry(f).f(a).f(b);
+  }
+
+  /**
+   * Curry a function of arity-8.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @param c An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H, I> F<D, F<E, F<F$, F<G, F<H, I>>>>> curry(
+      final F8<A, B, C, D, E, F$, G, H, I> f, final A a, final B b, final C c) {
+    return curry(f).f(a).f(b).f(c);
+  }
+
+  /**
+   * Curry a function of arity-8.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @param c An argument to the curried function.
+   * @param d An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H, I> F<E, F<F$, F<G, F<H, I>>>> curry(final F8<A, B, C, D, E, F$, G, H, I> f,
+                                                                              final A a, final B b, final C c,
+                                                                              final D d) {
+    return curry(f).f(a).f(b).f(c).f(d);
+  }
+
+  /**
+   * Curry a function of arity-8.
+   *
+   * @param f The function to curry.
+   * @param a An argument to the curried function.
+   * @param b An argument to the curried function.
+   * @param c An argument to the curried function.
+   * @param d An argument to the curried function.
+   * @param e An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H, I> F<F$, F<G, F<H, I>>> curry(final F8<A, B, C, D, E, F$, G, H, I> f,
+                                                                        final A a, final B b, final C c, final D d,
+                                                                        final E e) {
+    return curry(f).f(a).f(b).f(c).f(d).f(e);
+  }
+
+  /**
+   * Curry a function of arity-8.
+   *
+   * @param f  The function to curry.
+   * @param a  An argument to the curried function.
+   * @param b  An argument to the curried function.
+   * @param c  An argument to the curried function.
+   * @param d  An argument to the curried function.
+   * @param e  An argument to the curried function.
+   * @param f$ An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H, I> F<G, F<H, I>> curry(final F8<A, B, C, D, E, F$, G, H, I> f, final A a,
+                                                                 final B b, final C c, final D d, final E e,
+                                                                 final F$ f$) {
+    return curry(f).f(a).f(b).f(c).f(d).f(e).f(f$);
+  }
+
+  /**
+   * Curry a function of arity-7.
+   *
+   * @param f  The function to curry.
+   * @param a  An argument to the curried function.
+   * @param b  An argument to the curried function.
+   * @param c  An argument to the curried function.
+   * @param d  An argument to the curried function.
+   * @param e  An argument to the curried function.
+   * @param f$ An argument to the curried function.
+   * @param g  An argument to the curried function.
+   * @return A curried form of the given function.
+   */
+  public static <A, B, C, D, E, F$, G, H, I> F<H, I> curry(final F8<A, B, C, D, E, F$, G, H, I> f, final A a, final B b,
+                                                           final C c, final D d, final E e, final F$ f$, final G g) {
+    return curry(f).f(a).f(b).f(c).f(d).f(e).f(f$).f(g);
+  }
+
+  /**
+   * Uncurry a function of arity-8.
+   *
+   * @return An uncurried function.
+   */
+  public static <A, B, C, D, E, F$, G, H, I> F<F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>>, F8<A, B, C, D, E, F$, G, H, I>> uncurryF8() {
+    return new F<F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>>, F8<A, B, C, D, E, F$, G, H, I>>() {
+      public F8<A, B, C, D, E, F$, G, H, I> f(final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>> f) {
+        return uncurryF8(f);
+      }
+    };
+  }
+
+  /**
+   * Uncurry a function of arity-8.
+   *
+   * @param f The function to uncurry.
+   * @return An uncurried function.
+   */
+  public static <A, B, C, D, E, F$, G, H, I> F8<A, B, C, D, E, F$, G, H, I> uncurryF8(
+      final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>> f) {
+    return new F8<A, B, C, D, E, F$, G, H, I>() {
+      public I f(final A a, final B b, final C c, final D d, final E e, final F$ f$, final G g, final H h) {
+        return f.f(a).f(b).f(c).f(d).f(e).f(f$).f(g).f(h);
+      }
+    };
+  }
+
+  /**
+   * Binds the function in the second argument to the function in the first argument.
+   *
+   * @param ma A function whose argument type is the same as the argument type of the return value.
+   * @param f  A function whose argument type is the same as the return type of <em>ma</em>,
+   *           and yields the return value.
+   * @return A function that chains the given functions together such that the result of applying
+   *         <em>ma</em> to the argument is given to <i>f</i>, yielding a function
+   *         that is applied to the argument again.
+   */
+  public static <A, B, C> F<C, B> bind(final F<C, A> ma, final F<A, F<C, B>> f) {
+    return new F<C, B>() {
+      public B f(final C m) {
+        return f.f(ma.f(m)).f(m);
+      }
+    };
+  }
+
+  /**
+   * Performs function application within a higher-order function (applicative functor pattern).
+   *
+   * @param cab The higher-order function to apply a function to.
+   * @param ca  A function to apply within a higher-order function.
+   * @return A new function after applying the given higher-order function to the given function.
+   */
+  public static <A, B, C> F<C, B> apply(final F<C, F<A, B>> cab, final F<C, A> ca) {
+    return bind(cab, new F<F<A, B>, F<C, B>>() {
+      public F<C, B> f(final F<A, B> f) {
+        return compose(new F<A, B>() {
+          public B f(final A a) {
+            return f.f(a);
+          }
+        }, ca);
+      }
+    });
+  }
+
+  /**
+   * Binds the given function <em>f</em> to the values of the given functions, with a final join.
+   *
+   * @param ca A function to bind <em>f</em> function to.
+   * @param cb A function to bind <em>f</em> function to.
+   * @param f  The bound function to be composed with <em>ca</em> and then applied with <em>cb</em>
+   * @return A new function after performing the composition, then application.
+   */
+  public static <A, B, C, D> F<D, C> bind(final F<D, A> ca, final F<D, B> cb, final F<A, F<B, C>> f) {
+    return apply(compose(f, ca), cb);
+  }
+
+  /**
+   * Applies a given function over the arguments of another function of arity-2.
+   *
+   * @param a The function whose arguments to apply another function over.
+   * @param f The function to apply over the arguments of another function.
+   * @return A function whose arguments are fed through function f, before being passed to function a.
+   */
+  public static <A, B, C> F<B, F<B, C>> on(final F<A, F<A, C>> a, final F<B, A> f) {
+    return compose(compose(Function.<B, A, C>andThen().f(f), a), f);
+  }
+
+  /**
+   * Promotes a function of arity-2 to a higher-order function.
+   *
+   * @param f The function to promote.
+   * @return A function of arity-2 promoted to compose with two functions.
+   */
+  public static <A, B, C, D> F<F<D, A>, F<F<D, B>, F<D, C>>> lift(final F<A, F<B, C>> f) {
+    return curry(new F2<F<D, A>, F<D, B>, F<D, C>>() {
+      public F<D, C> f(final F<D, A> ca, final F<D, B> cb) {
+        return bind(ca, cb, f);
+      }
+    });
+  }
+
+  /**
+   * Joins two arguments of a function of arity-2 into one argument, yielding a function of arity-1.
+   *
+   * @param f A function whose arguments to join.
+   * @return A function of arity-1 whose argument is substituted for both parameters of <em>f</em>.
+   */
+  public static <A, B> F<B, A> join(final F<B, F<B, A>> f) {
+    return bind(f, Function.<F<B, A>>identity());
+  }
+
+
+  /**
+   * Partial application of the second argument to the supplied function to get a function of type
+   * <tt>A -> C</tt>. Same as <tt>flip(f).f(b)</tt>.
+   *
+   * @param f The function to partially apply.
+   * @param b The value to apply to the function.
+   * @return A new function based on <tt>f</tt> with its second argument applied.
+   */
+  public static <A, B, C> F<A, C> partialApply2(final F<A, F<B, C>> f, final B b) {
+    return new F<A, C>() {
+      public C f(final A a) {
+        return uncurryF2(f).f(a, b);
+      }
+    };
+  }
+
+  /**
+   * Partial application of the third argument to the supplied function to get a function of type
+   * <tt>A -> B -> D</tt>.
+   *
+   * @param f The function to partially apply.
+   * @param c The value to apply to the function.
+   * @return A new function based on <tt>f</tt> with its third argument applied.
+   */
+  public static <A, B, C, D> F<A, F<B, D>> partialApply3(final F<A, F<B, F<C, D>>> f, final C c) {
+    return new F<A, F<B, D>>() {
+      public F<B, D> f(final A a) {
+        return new F<B, D>() {
+          public D f(final B b) {
+            return uncurryF3(f).f(a, b, c);
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Partial application of the fourth argument to the supplied function to get a function of type
+   * <tt>A -> B -> C -> E</tt>.
+   *
+   * @param f The function to partially apply.
+   * @param d The value to apply to the function.
+   * @return A new function based on <tt>f</tt> with its fourth argument applied.
+   */
+  public static <A, B, C, D, E> F<A, F<B, F<C, E>>> partialApply4(final F<A, F<B, F<C, F<D, E>>>> f, final D d) {
+    return new F<A, F<B, F<C, E>>>() {
+      public F<B, F<C, E>> f(final A a) {
+        return new F<B, F<C, E>>() {
+          public F<C, E> f(final B b) {
+            return new F<C, E>() {
+              public E f(final C c) {
+                return uncurryF4(f).f(a, b, c, d);
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Partial application of the fifth argument to the supplied function to get a function of type
+   * <tt>A -> B -> C -> D -> F$</tt>.
+   *
+   * @param f The function to partially apply.
+   * @param e The value to apply to the function.
+   * @return A new function based on <tt>f</tt> with its fifth argument applied.
+   */
+  public static <A, B, C, D, E, F$> F<A, F<B, F<C, F<D, F$>>>> partialApply5(final F<A, F<B, F<C, F<D, F<E, F$>>>>> f,
+                                                                             final E e) {
+    return new F<A, F<B, F<C, F<D, F$>>>>() {
+      public F<B, F<C, F<D, F$>>> f(final A a) {
+        return new F<B, F<C, F<D, F$>>>() {
+          public F<C, F<D, F$>> f(final B b) {
+            return new F<C, F<D, F$>>() {
+              public F<D, F$> f(final C c) {
+                return new F<D, F$>() {
+                  public F$ f(final D d) {
+                    return uncurryF5(f).f(a, b, c, d, e);
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Partial application of the sixth argument to the supplied function to get a function of type
+   * <tt>A -> B -> C -> D -> E -> G</tt>.
+   *
+   * @param f  The function to partially apply.
+   * @param f$ The value to apply to the function.
+   * @return A new function based on <tt>f</tt> with its sixth argument applied.
+   */
+  public static <A, B, C, D, E, F$, G> F<A, F<B, F<C, F<D, F<E, G>>>>> partialApply6(
+      final F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>> f, final F$ f$) {
+    return new F<A, F<B, F<C, F<D, F<E, G>>>>>() {
+      public F<B, F<C, F<D, F<E, G>>>> f(final A a) {
+        return new F<B, F<C, F<D, F<E, G>>>>() {
+          public F<C, F<D, F<E, G>>> f(final B b) {
+            return new F<C, F<D, F<E, G>>>() {
+              public F<D, F<E, G>> f(final C c) {
+                return new F<D, F<E, G>>() {
+                  public F<E, G> f(final D d) {
+                    return new F<E, G>() {
+                      public G f(final E e) {
+                        return uncurryF6(f).f(a, b, c, d, e, f$);
+                      }
+                    };
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Partial application of the seventh argument to the supplied function to get a function of type
+   * <tt>A -> B -> C -> D -> E -> F$ -> H</tt>.
+   *
+   * @param f The function to partially apply.
+   * @param g The value to apply to the function.
+   * @return A new function based on <tt>f</tt> with its seventh argument applied.
+   */
+  public static <A, B, C, D, E, F$, G, H> F<A, F<B, F<C, F<D, F<E, F<F$, H>>>>>> partialApply7(
+      final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>> f, final G g) {
+    return new F<A, F<B, F<C, F<D, F<E, F<F$, H>>>>>>() {
+      public F<B, F<C, F<D, F<E, F<F$, H>>>>> f(final A a) {
+        return new F<B, F<C, F<D, F<E, F<F$, H>>>>>() {
+          public F<C, F<D, F<E, F<F$, H>>>> f(final B b) {
+            return new F<C, F<D, F<E, F<F$, H>>>>() {
+              public F<D, F<E, F<F$, H>>> f(final C c) {
+                return new F<D, F<E, F<F$, H>>>() {
+                  public F<E, F<F$, H>> f(final D d) {
+                    return new F<E, F<F$, H>>() {
+                      public F<F$, H> f(final E e) {
+                        return new F<F$, H>() {
+                          public H f(final F$ f$) {
+                            return uncurryF7(f).f(a, b, c, d, e, f$, g);
+                          }
+                        };
+                      }
+                    };
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * Partial application of the eigth argument to the supplied function to get a function of type
+   * <tt>A -> B -> C -> D -> E -> F$ -> G -> I</tt>.
+   *
+   * @param f The function to partially apply.
+   * @param h The value to apply to the function.
+   * @return A new function based on <tt>f</tt> with its eigth argument applied.
+   */
+  public static <A, B, C, D, E, F$, G, H, I> F<A, F<B, F<C, F<D, F<E, F<F$, F<G, I>>>>>>> partialApply8(
+      final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>> f, final H h) {
+    return new F<A, F<B, F<C, F<D, F<E, F<F$, F<G, I>>>>>>>() {
+      public F<B, F<C, F<D, F<E, F<F$, F<G, I>>>>>> f(final A a) {
+        return new F<B, F<C, F<D, F<E, F<F$, F<G, I>>>>>>() {
+          public F<C, F<D, F<E, F<F$, F<G, I>>>>> f(final B b) {
+            return new F<C, F<D, F<E, F<F$, F<G, I>>>>>() {
+              public F<D, F<E, F<F$, F<G, I>>>> f(final C c) {
+                return new F<D, F<E, F<F$, F<G, I>>>>() {
+                  public F<E, F<F$, F<G, I>>> f(final D d) {
+                    return new F<E, F<F$, F<G, I>>>() {
+                      public F<F$, F<G, I>> f(final E e) {
+                        return new F<F$, F<G, I>>() {
+                          public F<G, I> f(final F$ f$) {
+                            return new F<G, I>() {
+                              public I f(final G g) {
+                                return uncurryF8(f).f(a, b, c, d, e, f$, g, h);
+                              }
+                            };
+                          }
+                        };
+                      }
+                    };
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/Hash.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,556 @@
+package fj;
+
+import static fj.Function.compose;
+
+import fj.data.Array;
+import fj.data.Either;
+import fj.data.List;
+import fj.data.NonEmptyList;
+import fj.data.Option;
+import fj.data.Stream;
+import fj.data.Tree;
+import fj.data.Validation;
+import fj.data.vector.V2;
+import fj.data.vector.V3;
+import fj.data.vector.V4;
+import fj.data.vector.V5;
+import fj.data.vector.V6;
+import fj.data.vector.V7;
+import fj.data.vector.V8;
+
+/**
+ * Produces a hash code for an object which should attempt uniqueness.
+ *
+ * @version %build.number%
+ */
+public final class Hash<A> {
+  private final F<A, Integer> f;
+
+  private Hash(final F<A, Integer> f) {
+    this.f = f;
+  }
+
+  /**
+   * Compute the hash of the given value.
+   *
+   * @param a The value to compute the hash value for.
+   * @return The hash value.
+   */
+  public int hash(final A a) {
+    return f.f(a);
+  }
+
+  /**
+   * Maps the given function across this hash as a contra-variant functor.
+   *
+   * @param g The function to map.
+   * @return A new hash.
+   */
+  public <B> Hash<B> comap(final F<B, A> g) {
+    return new Hash<B>(compose(f, g));
+  }
+
+  /**
+   * Construct a hash with the given hash function.
+   *
+   * @param f The function to construct the hash with.
+   * @return A hash that uses the given function.
+   */
+  public static <A> Hash<A> hash(final F<A, Integer> f) {
+    return new Hash<A>(f);
+  }
+
+  /**
+   * A hash that uses {@link Object#hashCode()}.
+   *
+   * @return A hash that uses {@link Object#hashCode()}.
+   */
+  public static <A> Hash<A> anyHash() {
+    return new Hash<A>(new F<A, Integer>() {
+      public Integer f(final A a) {
+        return a.hashCode();
+      }
+    });
+  }
+
+  /**
+   * A hash instance for the <code>boolean</code> type.
+   */
+  public static final Hash<Boolean> booleanHash = anyHash();
+
+  /**
+   * A hash instance for the <code>byte</code> type.
+   */
+  public static final Hash<Byte> byteHash = anyHash();
+
+  /**
+   * A hash instance for the <code>char</code> type.
+   */
+  public static final Hash<Character> charHash = anyHash();
+
+  /**
+   * A hash instance for the <code>double</code> type.
+   */
+  public static final Hash<Double> doubleHash = anyHash();
+
+  /**
+   * A hash instance for the <code>float</code> type.
+   */
+  public static final Hash<Float> floatHash = anyHash();
+
+  /**
+   * A hash instance for the <code>int</code> type.
+   */
+  public static final Hash<Integer> intHash = anyHash();
+
+  /**
+   * A hash instance for the <code>long</code> type.
+   */
+  public static final Hash<Long> longHash = anyHash();
+
+  /**
+   * A hash instance for the <code>short</code> type.
+   */
+  public static final Hash<Short> shortHash = anyHash();
+
+  /**
+   * A hash instance for the <code>String</code> type.
+   */
+  public static final Hash<String> stringHash = anyHash();
+
+  /**
+   * A hash instance for the {@link StringBuffer} type.
+   */
+  public static final Hash<StringBuffer> stringBufferHash = new Hash<StringBuffer>(new F<StringBuffer, Integer>() {
+    public Integer f(final StringBuffer sb) {
+      final int p = 419;
+      int r = 239;
+
+      for (int i = 0; i < sb.length(); i++)
+        r = p * r + sb.charAt(i);
+
+      return r;
+    }
+  });
+
+  /**
+   * A hash instance for the {@link StringBuilder} type.
+   */
+  public static final Hash<StringBuilder> stringBuilderHash = new Hash<StringBuilder>(new F<StringBuilder, Integer>() {
+    public Integer f(final StringBuilder sb) {
+      final int p = 419;
+      int r = 239;
+
+      for (int i = 0; i < sb.length(); i++)
+        r = p * r + sb.charAt(i);
+
+      return r;
+    }
+  });
+
+  /**
+   * A hash instance for the {@link Either} type.
+   *
+   * @param ha Hash the left side of <code>Either</code>.
+   * @param hb Hash the right side of <code>Either</code>.
+   * @return A hash instance for the {@link Either} type.
+   */
+  public static <A, B> Hash<Either<A, B>> eitherHash(final Hash<A> ha, final Hash<B> hb) {
+    return new Hash<Either<A, B>>(new F<Either<A, B>, Integer>() {
+      public Integer f(final Either<A, B> e) {
+        return e.isLeft() ? ha.hash(e.left().value()) : hb.hash(e.right().value());
+      }
+    });
+  }
+
+  /**
+   * A hash instance for the {@link Validation} type.
+   *
+   * @param ha Hash the failing side of <code>Validation</code>.
+   * @param hb Hash the succeeding side of <code>Validation</code>.
+   * @return A hash instance for the {@link Validation} type.
+   */
+  public static <A, B> Hash<Validation<A, B>> validationHash(final Hash<A> ha, final Hash<B> hb) {
+    return eitherHash(ha, hb).comap(Validation.<A, B>either());
+  }
+
+  /**
+   * A hash instance for the {@link List} type.
+   *
+   * @param ha A hash for the elements of the list.
+   * @return A hash instance for the {@link List} type.
+   */
+  public static <A> Hash<List<A>> listHash(final Hash<A> ha) {
+    return new Hash<List<A>>(new F<List<A>, Integer>() {
+      public Integer f(final List<A> as) {
+        final int p = 419;
+        int r = 239;
+        List<A> aas = as;
+
+        while (!aas.isEmpty()) {
+          r = p * r + ha.hash(aas.head());
+          aas = aas.tail();
+        }
+
+        return r;
+      }
+    });
+  }
+
+  /**
+   * A hash instance for the {@link NonEmptyList} type.
+   *
+   * @param ha A hash for the elements of the non-empty list.
+   * @return A hash instance for the {@link NonEmptyList} type.
+   */
+  public static <A> Hash<NonEmptyList<A>> nonEmptyListHash(final Hash<A> ha) {
+    return listHash(ha).comap(NonEmptyList.<A>toList_());
+  }
+
+  /**
+   * A hash instance for the {@link Option} type.
+   *
+   * @param ha A hash for the element of the optional value.
+   * @return A hash instance for the {@link Option} type.
+   */
+  public static <A> Hash<Option<A>> optionHash(final Hash<A> ha) {
+    return new Hash<Option<A>>(new F<Option<A>, Integer>() {
+      public Integer f(final Option<A> o) {
+        return o.isNone() ? 0 : ha.hash(o.some());
+      }
+    });
+  }
+
+  /**
+   * A hash instance for the {@link Stream} type.
+   *
+   * @param ha A hash for the elements of the stream.
+   * @return A hash instance for the {@link Stream} type.
+   */
+  public static <A> Hash<Stream<A>> streamHash(final Hash<A> ha) {
+    return new Hash<Stream<A>>(new F<Stream<A>, Integer>() {
+      public Integer f(final Stream<A> as) {
+        final int p = 419;
+        int r = 239;
+        Stream<A> aas = as;
+
+        while (!aas.isEmpty()) {
+          r = p * r + ha.hash(aas.head());
+          aas = aas.tail()._1();
+        }
+
+        return r;
+      }
+    });
+  }
+
+  /**
+   * A hash instance for the {@link Array} type.
+   *
+   * @param ha A hash for the elements of the array.
+   * @return A hash instance for the {@link Array} type.
+   */
+  public static <A> Hash<Array<A>> arrayHash(final Hash<A> ha) {
+    return new Hash<Array<A>>(new F<Array<A>, Integer>() {
+      public Integer f(final Array<A> as) {
+        final int p = 419;
+        int r = 239;
+
+        for (int i = 0; i < as.length(); i++) {
+          r = p * r + ha.hash(as.get(i));
+        }
+
+        return r;
+      }
+    });
+  }
+
+  /**
+   * A hash instance for the {@link Tree} type.
+   *
+   * @param ha A hash for the elements of the tree.
+   * @return A hash instance for the {@link Tree} type.
+   */
+  public static <A> Hash<Tree<A>> treeHash(final Hash<A> ha) {
+    return streamHash(ha).comap(Tree.<A>flatten_());
+  }
+
+  /**
+   * A hash instance for a product-1.
+   *
+   * @param ha A hash for the first element of the product.
+   * @return A hash instance for a product-1.
+   */
+  public static <A> Hash<P1<A>> p1Hash(final Hash<A> ha) {
+    return ha.comap(P1.<A>__1());
+  }
+
+  /**
+   * A hash instance for a product-2.
+   *
+   * @param ha A hash for the first element of the product.
+   * @param hb A hash for the second element of the product.
+   * @return A hash instance for a product-2.
+   */
+  public static <A, B> Hash<P2<A, B>> p2Hash(final Hash<A> ha, final Hash<B> hb) {
+    return new Hash<P2<A, B>>(new F<P2<A, B>, Integer>() {
+      public Integer f(final P2<A, B> p2) {
+        final int p = 419;
+        int r = 239;
+
+        r = p * r + ha.hash(p2._1());
+        r = p * r + hb.hash(p2._2());
+
+        return r;
+      }
+    });
+  }
+
+  /**
+   * A hash instance for a product-3.
+   *
+   * @param ha A hash for the first element of the product.
+   * @param hb A hash for the second element of the product.
+   * @param hc A hash for the third element of the product.
+   * @return A hash instance for a product-3.
+   */
+  public static <A, B, C> Hash<P3<A, B, C>> p3Hash(final Hash<A> ha, final Hash<B> hb, final Hash<C> hc) {
+    return new Hash<P3<A, B, C>>(new F<P3<A, B, C>, Integer>() {
+      public Integer f(final P3<A, B, C> p3) {
+        final int p = 419;
+        int r = 239;
+
+        r = p * r + ha.hash(p3._1());
+        r = p * r + hb.hash(p3._2());
+        r = p * r + hc.hash(p3._3());
+
+        return r;
+      }
+    });
+  }
+
+  /**
+   * A hash instance for a product-4.
+   *
+   * @param ha A hash for the first element of the product.
+   * @param hb A hash for the second element of the product.
+   * @param hc A hash for the third element of the product.
+   * @param hd A hash for the fourth element of the product.
+   * @return A hash instance for a product-4.
+   */
+  public static <A, B, C, D> Hash<P4<A, B, C, D>> p4Hash(final Hash<A> ha, final Hash<B> hb, final Hash<C> hc,
+                                                         final Hash<D> hd) {
+    return new Hash<P4<A, B, C, D>>(new F<P4<A, B, C, D>, Integer>() {
+      public Integer f(final P4<A, B, C, D> p4) {
+        final int p = 419;
+        int r = 239;
+
+        r = p * r + ha.hash(p4._1());
+        r = p * r + hb.hash(p4._2());
+        r = p * r + hc.hash(p4._3());
+        r = p * r + hd.hash(p4._4());
+
+        return r;
+      }
+    });
+  }
+
+  /**
+   * A hash instance for a product-5.
+   *
+   * @param ha A hash for the first element of the product.
+   * @param hb A hash for the second element of the product.
+   * @param hc A hash for the third element of the product.
+   * @param hd A hash for the fourth element of the product.
+   * @param he A hash for the fifth element of the product.
+   * @return A hash instance for a product-5.
+   */
+  public static <A, B, C, D, E> Hash<P5<A, B, C, D, E>> p5Hash(final Hash<A> ha, final Hash<B> hb, final Hash<C> hc,
+                                                               final Hash<D> hd, final Hash<E> he) {
+    return new Hash<P5<A, B, C, D, E>>(new F<P5<A, B, C, D, E>, Integer>() {
+      public Integer f(final P5<A, B, C, D, E> p5) {
+        final int p = 419;
+        int r = 239;
+
+        r = p * r + ha.hash(p5._1());
+        r = p * r + hb.hash(p5._2());
+        r = p * r + hc.hash(p5._3());
+        r = p * r + hd.hash(p5._4());
+        r = p * r + he.hash(p5._5());
+
+        return r;
+      }
+    });
+  }
+
+  /**
+   * A hash instance for a product-6.
+   *
+   * @param ha A hash for the first element of the product.
+   * @param hb A hash for the second element of the product.
+   * @param hc A hash for the third element of the product.
+   * @param hd A hash for the fourth element of the product.
+   * @param he A hash for the fifth element of the product.
+   * @param hf A hash for the sixth element of the product.
+   * @return A hash instance for a product-6.
+   */
+  public static <A, B, C, D, E, F$> Hash<P6<A, B, C, D, E, F$>> p6Hash(final Hash<A> ha, final Hash<B> hb,
+                                                                       final Hash<C> hc, final Hash<D> hd,
+                                                                       final Hash<E> he, final Hash<F$> hf) {
+    return new Hash<P6<A, B, C, D, E, F$>>(new F<P6<A, B, C, D, E, F$>, Integer>() {
+      public Integer f(final P6<A, B, C, D, E, F$> p6) {
+        final int p = 419;
+        int r = 239;
+
+        r = p * r + ha.hash(p6._1());
+        r = p * r + hb.hash(p6._2());
+        r = p * r + hc.hash(p6._3());
+        r = p * r + hd.hash(p6._4());
+        r = p * r + he.hash(p6._5());
+        r = p * r + hf.hash(p6._6());
+
+        return r;
+      }
+    });
+  }
+
+  /**
+   * A hash instance for a product-7.
+   *
+   * @param ha A hash for the first element of the product.
+   * @param hb A hash for the second element of the product.
+   * @param hc A hash for the third element of the product.
+   * @param hd A hash for the fourth element of the product.
+   * @param he A hash for the fifth element of the product.
+   * @param hf A hash for the sixth element of the product.
+   * @param hg A hash for the seventh element of the product.
+   * @return A hash instance for a product-7.
+   */
+  public static <A, B, C, D, E, F$, G> Hash<P7<A, B, C, D, E, F$, G>> p7Hash(final Hash<A> ha, final Hash<B> hb,
+                                                                             final Hash<C> hc, final Hash<D> hd,
+                                                                             final Hash<E> he, final Hash<F$> hf,
+                                                                             final Hash<G> hg) {
+    return new Hash<P7<A, B, C, D, E, F$, G>>(new F<P7<A, B, C, D, E, F$, G>, Integer>() {
+      public Integer f(final P7<A, B, C, D, E, F$, G> p7) {
+        final int p = 419;
+        int r = 239;
+
+        r = p * r + ha.hash(p7._1());
+        r = p * r + hb.hash(p7._2());
+        r = p * r + hc.hash(p7._3());
+        r = p * r + hd.hash(p7._4());
+        r = p * r + he.hash(p7._5());
+        r = p * r + hf.hash(p7._6());
+        r = p * r + hg.hash(p7._7());
+
+        return r;
+      }
+    });
+  }
+
+  /**
+   * A hash instance for a product-8.
+   *
+   * @param ha A hash for the first element of the product.
+   * @param hb A hash for the second element of the product.
+   * @param hc A hash for the third element of the product.
+   * @param hd A hash for the fourth element of the product.
+   * @param he A hash for the fifth element of the product.
+   * @param hf A hash for the sixth element of the product.
+   * @param hg A hash for the seventh element of the product.
+   * @param hh A hash for the eighth element of the product.
+   * @return A hash instance for a product-8.
+   */
+  public static <A, B, C, D, E, F$, G, H> Hash<P8<A, B, C, D, E, F$, G, H>> p8Hash(final Hash<A> ha, final Hash<B> hb,
+                                                                                   final Hash<C> hc, final Hash<D> hd,
+                                                                                   final Hash<E> he, final Hash<F$> hf,
+                                                                                   final Hash<G> hg, final Hash<H> hh) {
+    return new Hash<P8<A, B, C, D, E, F$, G, H>>(new F<P8<A, B, C, D, E, F$, G, H>, Integer>() {
+      public Integer f(final P8<A, B, C, D, E, F$, G, H> p8) {
+        final int p = 419;
+        int r = 239;
+
+        r = p * r + ha.hash(p8._1());
+        r = p * r + hb.hash(p8._2());
+        r = p * r + hc.hash(p8._3());
+        r = p * r + hd.hash(p8._4());
+        r = p * r + he.hash(p8._5());
+        r = p * r + hf.hash(p8._6());
+        r = p * r + hg.hash(p8._7());
+        r = p * r + hh.hash(p8._8());
+
+        return r;
+      }
+    });
+  }
+
+  /**
+   * A hash instance for a vector-2.
+   *
+   * @param ea A hash for the elements of the vector.
+   * @return A hash instance for a vector-2.
+   */
+  public static <A> Hash<V2<A>> v2Hash(final Hash<A> ea) {
+    return streamHash(ea).comap(V2.<A>toStream_());
+  }
+
+  /**
+   * A hash instance for a vector-3.
+   *
+   * @param ea A hash for the elements of the vector.
+   * @return A hash instance for a vector-3.
+   */
+  public static <A> Hash<V3<A>> v3Hash(final Hash<A> ea) {
+    return streamHash(ea).comap(V3.<A>toStream_());
+  }
+
+  /**
+   * A hash instance for a vector-4.
+   *
+   * @param ea A hash for the elements of the vector.
+   * @return A hash instance for a vector-4.
+   */
+  public static <A> Hash<V4<A>> v4Hash(final Hash<A> ea) {
+    return streamHash(ea).comap(V4.<A>toStream_());
+  }
+
+  /**
+   * A hash instance for a vector-5.
+   *
+   * @param ea A hash for the elements of the vector.
+   * @return A hash instance for a vector-5.
+   */
+  public static <A> Hash<V5<A>> v5Hash(final Hash<A> ea) {
+    return streamHash(ea).comap(V5.<A>toStream_());
+  }
+
+  /**
+   * A hash instance for a vector-6.
+   *
+   * @param ea A hash for the elements of the vector.
+   * @return A hash instance for a vector-6.
+   */
+  public static <A> Hash<V6<A>> v6Hash(final Hash<A> ea) {
+    return streamHash(ea).comap(V6.<A>toStream_());
+  }
+
+  /**
+   * A hash instance for a vector-7.
+   *
+   * @param ea A hash for the elements of the vector.
+   * @return A hash instance for a vector-7.
+   */
+  public static <A> Hash<V7<A>> v7Hash(final Hash<A> ea) {
+    return streamHash(ea).comap(V7.<A>toStream_());
+  }
+
+  /**
+   * A hash instance for a vector-8.
+   *
+   * @param ea A hash for the elements of the vector.
+   * @return A hash instance for a vector-8.
+   */
+  public static <A> Hash<V8<A>> v8Hash(final Hash<A> ea) {
+    return streamHash(ea).comap(V8.<A>toStream_());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/LcgRng.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,47 @@
+package fj;
+
+/**
+ * Created by MarkPerry on 7/07/2014.
+ *
+ * https://en.wikipedia.org/wiki/Linear_congruential_generator
+ */
+public class LcgRng extends Rng {
+
+	private final Long seed;
+
+    public LcgRng() {
+        this(System.currentTimeMillis());
+    }
+
+	public LcgRng(long s) {
+		seed = s;
+	}
+
+    public long getSeed() {
+        return seed;
+    }
+
+	public P2<Rng, Integer> nextInt() {
+        P2<Rng, Long> p = nextLong();
+        int i = (int) p._2().longValue();
+        return P.p(p._1(), i);
+	}
+
+
+	public P2<Rng, Long> nextLong() {
+        P2<Long, Long> p = nextLong(seed);
+        return P.p(new LcgRng(p._1()), p._2());
+    }
+
+    /**
+     *
+     * @param seed
+     * @return Product of Seed and value
+     */
+    static P2<Long, Long> nextLong(long seed) {
+        long newSeed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFFL;
+        long n = (Long) (newSeed >>> 16);
+        return P.p(newSeed, n);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/Monoid.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,387 @@
+package fj;
+
+import static fj.Function.curry;
+import static fj.Function.compose;
+import static fj.Function.flip;
+import fj.data.Array;
+import fj.data.List;
+import fj.data.Natural;
+import fj.data.Option;
+import fj.data.Set;
+import fj.data.Stream;
+import static fj.data.Stream.iterableStream;
+
+import java.math.BigInteger;
+import java.math.BigDecimal;
+
+/**
+ * A monoid abstraction to be defined across types of the given type argument. Implementations must
+ * follow the monoidal laws:
+ * <ul>
+ * <li><em>Left Identity</em>; forall x. sum(zero(), x) == x</li>
+ * <li><em>Right Identity</em>; forall x. sum(x, zero()) == x</li>
+ * <li><em>Associativity</em>; forall x. forall y. forall z. sum(sum(x, y), z) == sum(x, sum(y, z))</li>
+ * </ul>
+ *
+ * @version %build.number%
+ */
+public final class Monoid<A> {
+  private final F<A, F<A, A>> sum;
+  private final A zero;
+
+  private Monoid(final F<A, F<A, A>> sum, final A zero) {
+    this.sum = sum;
+    this.zero = zero;
+  }
+
+  /**
+   * Returns a semigroup projection of this monoid.
+   *
+   * @return A semigroup projection of this monoid.
+   */
+  public Semigroup<A> semigroup() {
+    return Semigroup.semigroup(sum);
+  }
+
+  /**
+   * Sums the two given arguments.
+   *
+   * @param a1 A value to sum with another.
+   * @param a2 A value to sum with another.
+   * @return The of the two given arguments.
+   */
+  public A sum(final A a1, final A a2) {
+    return sum.f(a1).f(a2);
+  }
+
+  /**
+   * Returns a function that sums the given value according to this monoid.
+   *
+   * @param a1 The value to sum.
+   * @return A function that sums the given value according to this monoid.
+   */
+  public F<A, A> sum(final A a1) {
+    return sum.f(a1);
+  }
+
+  /**
+   * Returns a function that sums according to this monoid.
+   *
+   * @return A function that sums according to this monoid.
+   */
+  public F<A, F<A, A>> sum() {
+    return sum;
+  }
+
+  /**
+   * The zero value for this monoid.
+   *
+   * @return The zero value for this monoid.
+   */
+  public A zero() {
+    return zero;
+  }
+
+  /**
+   * Sums the given values with right-fold.
+   *
+   * @param as The values to sum.
+   * @return The sum of the given values.
+   */
+  public A sumRight(final List<A> as) {
+    return as.foldRight(sum, zero);
+  }
+
+  /**
+   * Sums the given values with right-fold.
+   *
+   * @param as The values to sum.
+   * @return The sum of the given values.
+   */
+  public A sumRight(final Stream<A> as) {
+    return as.foldRight(new F2<A, P1<A>, A>() {
+      public A f(final A a, final P1<A> ap1) {
+        return sum(a, ap1._1());
+      }
+    }, zero);
+  }
+
+  /**
+   * Sums the given values with left-fold.
+   *
+   * @param as The values to sum.
+   * @return The sum of the given values.
+   */
+  public A sumLeft(final List<A> as) {
+    return as.foldLeft(sum, zero);
+  }
+
+  /**
+   * Sums the given values with left-fold.
+   *
+   * @param as The values to sum.
+   * @return The sum of the given values.
+   */
+  public A sumLeft(final Stream<A> as) {
+    return as.foldLeft(sum, zero);
+  }
+
+  /**
+   * Returns a function that sums the given values with left-fold.
+   *
+   * @return a function that sums the given values with left-fold.
+   */
+  public F<List<A>, A> sumLeft() {
+    return new F<List<A>, A>() {
+      public A f(final List<A> as) {
+        return sumLeft(as);
+      }
+    };
+  }
+
+  /**
+   * Returns a function that sums the given values with right-fold.
+   *
+   * @return a function that sums the given values with right-fold.
+   */
+  public F<List<A>, A> sumRight() {
+    return new F<List<A>, A>() {
+      public A f(final List<A> as) {
+        return sumRight(as);
+      }
+    };
+  }
+
+  /**
+   * Returns a function that sums the given values with left-fold.
+   *
+   * @return a function that sums the given values with left-fold.
+   */
+  public F<Stream<A>, A> sumLeftS() {
+    return new F<Stream<A>, A>() {
+      public A f(final Stream<A> as) {
+        return sumLeft(as);
+      }
+    };
+  }
+
+  /**
+   * Intersperses the given value between each two elements of the iterable, and sums the result.
+   *
+   * @param as An iterable of values to sum.
+   * @param a  The value to intersperse between values of the given iterable.
+   * @return The sum of the given values and the interspersed value.
+   */
+  public A join(final Iterable<A> as, final A a) {
+    final Stream<A> s = iterableStream(as);
+    return s.isEmpty() ?
+           zero :
+           s.foldLeft1(compose(sum, flip(sum).f(a)));
+  }
+
+  /**
+   * Constructs a monoid from the given sum function and zero value, which must follow the monoidal
+   * laws.
+   *
+   * @param sum  The sum function for the monoid.
+   * @param zero The zero for the monoid.
+   * @return A monoid instance that uses the given sun function and zero value.
+   */
+  public static <A> Monoid<A> monoid(final F<A, F<A, A>> sum, final A zero) {
+    return new Monoid<A>(sum, zero);
+  }
+
+  /**
+   * Constructs a monoid from the given sum function and zero value, which must follow the monoidal
+   * laws.
+   *
+   * @param sum  The sum function for the monoid.
+   * @param zero The zero for the monoid.
+   * @return A monoid instance that uses the given sun function and zero value.
+   */
+  public static <A> Monoid<A> monoid(final F2<A, A, A> sum, final A zero) {
+    return new Monoid<A>(curry(sum), zero);
+  }
+
+  /**
+   * Constructs a monoid from the given semigroup and zero value, which must follow the monoidal laws.
+   *
+   * @param s    The semigroup for the monoid.
+   * @param zero The zero for the monoid.
+   * @return A monoid instance that uses the given sun function and zero value.
+   */
+  public static <A> Monoid<A> monoid(final Semigroup<A> s, final A zero) {
+    return new Monoid<A>(s.sum(), zero);
+  }
+
+  /**
+   * A monoid that adds integers.
+   */
+  public static final Monoid<Integer> intAdditionMonoid = monoid(Semigroup.intAdditionSemigroup, 0);
+
+  /**
+   * A monoid that multiplies integers.
+   */
+  public static final Monoid<Integer> intMultiplicationMonoid = monoid(Semigroup.intMultiplicationSemigroup, 1);
+
+  /**
+   * A monoid that adds doubles.
+   */
+  public static final Monoid<Double> doubleAdditionMonoid = monoid(Semigroup.doubleAdditionSemigroup, 0.0);
+
+  /**
+   * A monoid that multiplies doubles.
+   */
+  public static final Monoid<Double> doubleMultiplicationMonoid = monoid(Semigroup.doubleMultiplicationSemigroup, 1.0);
+
+  /**
+   * A monoid that adds big integers.
+   */
+  public static final Monoid<BigInteger> bigintAdditionMonoid = monoid(Semigroup.bigintAdditionSemigroup, BigInteger.ZERO);
+
+  /**
+   * A monoid that multiplies big integers.
+   */
+  public static final Monoid<BigInteger> bigintMultiplicationMonoid =
+      monoid(Semigroup.bigintMultiplicationSemigroup, BigInteger.ONE);
+
+  /**
+   * A monoid that adds big decimals.
+   */
+  public static final Monoid<BigDecimal> bigdecimalAdditionMonoid =
+      monoid(Semigroup.bigdecimalAdditionSemigroup, BigDecimal.ZERO);
+
+  /**
+   * A monoid that multiplies big decimals.
+   */
+  public static final Monoid<BigDecimal> bigdecimalMultiplicationMonoid =
+      monoid(Semigroup.bigdecimalMultiplicationSemigroup, BigDecimal.ONE);
+
+  /**
+   * A monoid that adds natural numbers.
+   */
+  public static final Monoid<Natural> naturalAdditionMonoid =
+      monoid(Semigroup.naturalAdditionSemigroup, Natural.ZERO);
+
+  /**
+   * A monoid that multiplies natural numbers.
+   */
+  public static final Monoid<Natural> naturalMultiplicationMonoid =
+      monoid(Semigroup.naturalMultiplicationSemigroup, Natural.ONE);
+
+  /**
+   * A monoid that adds longs.
+   */
+  public static final Monoid<Long> longAdditionMonoid = monoid(Semigroup.longAdditionSemigroup, 0L);
+
+  /**
+   * A monoid that multiplies longs.
+   */
+  public static final Monoid<Long> longMultiplicationMonoid = monoid(Semigroup.longMultiplicationSemigroup, 1L);
+
+  /**
+   * A monoid that ORs booleans.
+   */
+  public static final Monoid<Boolean> disjunctionMonoid = monoid(Semigroup.disjunctionSemigroup, false);
+
+  /**
+   * A monoid that XORs booleans.
+   */
+  public static final Monoid<Boolean> exclusiveDisjunctionMonoid = monoid(Semigroup.exclusiveDisjunctionSemiGroup, false);
+
+  /**
+   * A monoid that ANDs booleans.
+   */
+  public static final Monoid<Boolean> conjunctionMonoid = monoid(Semigroup.conjunctionSemigroup, true);
+
+  /**
+   * A monoid that appends strings.
+   */
+  public static final Monoid<String> stringMonoid = monoid(Semigroup.stringSemigroup, "");
+
+  /**
+   * A monoid that appends string buffers.
+   */
+  public static final Monoid<StringBuffer> stringBufferMonoid = monoid(Semigroup.stringBufferSemigroup, new StringBuffer());
+
+  /**
+   * A monoid that appends string builders.
+   */
+  public static final Monoid<StringBuilder> stringBuilderMonoid = monoid(Semigroup.stringBuilderSemigroup, new StringBuilder());
+
+  /**
+   * A monoid for functions.
+   *
+   * @param mb The monoid for the function codomain.
+   * @return A monoid for functions.
+   */
+  public static <A, B> Monoid<F<A, B>> functionMonoid(final Monoid<B> mb) {
+    return monoid(Semigroup.<A, B>functionSemigroup(mb.semigroup()), Function.<A, B>constant(mb.zero));
+  }
+
+  /**
+   * A monoid for lists.
+   *
+   * @return A monoid for lists.
+   */
+  public static <A> Monoid<List<A>> listMonoid() {
+    return monoid(Semigroup.<A>listSemigroup(), List.<A>nil());
+  }
+
+  /**
+   * A monoid for options.
+   *
+   * @return A monoid for options.
+   */
+  public static <A> Monoid<Option<A>> optionMonoid() {
+    return monoid(Semigroup.<A>optionSemigroup(), Option.<A>none());
+  }
+
+  /**
+   * A monoid for options that take the first available value.
+   *
+   * @return A monoid for options that take the first available value.
+   */
+  public static <A> Monoid<Option<A>> firstOptionMonoid() {
+    return monoid(Semigroup.<A>firstOptionSemigroup(), Option.<A>none());
+  }
+
+  /**
+   * A monoid for options that take the last available value.
+   *
+   * @return A monoid for options that take the last available value.
+   */
+  public static <A> Monoid<Option<A>> lastOptionMonoid() {
+    return monoid(Semigroup.<A>lastOptionSemigroup(), Option.<A>none());
+  }
+
+  /**
+   * A monoid for streams.
+   *
+   * @return A monoid for streams.
+   */
+  public static <A> Monoid<Stream<A>> streamMonoid() {
+    return monoid(Semigroup.<A>streamSemigroup(), Stream.<A>nil());
+  }
+
+  /**
+   * A monoid for arrays.
+   *
+   * @return A monoid for arrays.
+   */
+  @SuppressWarnings({"unchecked"})
+  public static <A> Monoid<Array<A>> arrayMonoid() {
+    return monoid(Semigroup.<A>arraySemigroup(), Array.<A>empty());
+  }
+
+  /**
+   * A monoid for sets.
+   *
+   * @param o An order for set elements.
+   * @return A monoid for sets whose elements have the given order.
+   */
+  public static <A> Monoid<Set<A>> setMonoid(final Ord<A> o) {
+    return monoid(Semigroup.<A>setSemigroup(), Set.empty(o));
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/Ord.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,685 @@
+package fj;
+
+import fj.data.Array;
+import fj.data.Either;
+import fj.data.List;
+import fj.data.Natural;
+import fj.data.NonEmptyList;
+import fj.data.Option;
+import fj.data.Set;
+import fj.data.Stream;
+import fj.data.Validation;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import static fj.Function.curry;
+
+/**
+ * Tests for ordering between two objects.
+ *
+ * @version %build.number%
+ */
+public final class Ord<A> {
+  private final F<A, F<A, Ordering>> f;
+
+  private Ord(final F<A, F<A, Ordering>> f) {
+    this.f = f;
+  }
+
+  /**
+   * First-class ordering.
+   *
+   * @return A function that returns an ordering for its arguments.
+   */
+  public F<A, F<A, Ordering>> compare() {
+    return f;
+  }
+
+  /**
+   * Returns an ordering for the given arguments.
+   *
+   * @param a1 An instance to compare for ordering to another.
+   * @param a2 An instance to compare for ordering to another.
+   * @return An ordering for the given arguments.
+   */
+  public Ordering compare(final A a1, final A a2) {
+    return f.f(a1).f(a2);
+  }
+
+  /**
+   * Returns <code>true</code> if the given arguments are equal, <code>false</code> otherwise.
+   *
+   * @param a1 An instance to compare for equality to another.
+   * @param a2 An instance to compare for equality to another.
+   * @return <code>true</code> if the given arguments are equal, <code>false</code> otherwise.
+   */
+  public boolean eq(final A a1, final A a2) {
+    return compare(a1, a2) == Ordering.EQ;
+  }
+
+  /**
+   * Returns an <code>Equal</code> for this order.
+   *
+   * @return An <code>Equal</code> for this order.
+   */
+  public Equal<A> equal() {
+    return Equal.equal(curry(new F2<A, A, Boolean>() {
+      public Boolean f(final A a1, final A a2) {
+        return eq(a1, a2);
+      }
+    }));
+  }
+
+  /**
+   * Maps the given function across this ord as a contra-variant functor.
+   *
+   * @param f The function to map.
+   * @return A new ord.
+   */
+  public <B> Ord<B> comap(final F<B, A> f) {
+    return ord(F1Functions.o(F1Functions.o(F1Functions.<B, A, Ordering>andThen(f), this.f), f));
+  }
+
+  /**
+   * Returns <code>true</code> if the first given argument is less than the second given argument,
+   * <code>false</code> otherwise.
+   *
+   * @param a1 An instance to compare for ordering to another.
+   * @param a2 An instance to compare for ordering to another.
+   * @return <code>true</code> if the first given argument is less than the second given argument,
+   *         <code>false</code> otherwise.
+   */
+  public boolean isLessThan(final A a1, final A a2) {
+    return compare(a1, a2) == Ordering.LT;
+  }
+
+  /**
+   * Returns <code>true</code> if the first given argument is greater than the second given
+   * argument, <code>false</code> otherwise.
+   *
+   * @param a1 An instance to compare for ordering to another.
+   * @param a2 An instance to compare for ordering to another.
+   * @return <code>true</code> if the first given argument is greater than the second given
+   *         argument, <code>false</code> otherwise.
+   */
+  public boolean isGreaterThan(final A a1, final A a2) {
+    return compare(a1, a2) == Ordering.GT;
+  }
+
+  /**
+   * Returns a function that returns true if its argument is less than the argument to this method.
+   *
+   * @param a A value to compare against.
+   * @return A function that returns true if its argument is less than the argument to this method.
+   */
+  public F<A, Boolean> isLessThan(final A a) {
+    return new F<A, Boolean>() {
+      public Boolean f(final A a2) {
+        return compare(a2, a) == Ordering.LT;
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns true if its argument is greater than than the argument to this method.
+   *
+   * @param a A value to compare against.
+   * @return A function that returns true if its argument is greater than the argument to this method.
+   */
+  public F<A, Boolean> isGreaterThan(final A a) {
+    return new F<A, Boolean>() {
+      public Boolean f(final A a2) {
+        return compare(a2, a) == Ordering.GT;
+      }
+    };
+  }
+
+  /**
+   * Returns the greater of its two arguments.
+   *
+   * @param a1 A value to compare with another.
+   * @param a2 A value to compare with another.
+   * @return The greater of the two values.
+   */
+  public A max(final A a1, final A a2) {
+    return isGreaterThan(a1, a2) ? a1 : a2;
+  }
+
+
+  /**
+   * Returns the lesser of its two arguments.
+   *
+   * @param a1 A value to compare with another.
+   * @param a2 A value to compare with another.
+   * @return The lesser of the two values.
+   */
+  public A min(final A a1, final A a2) {
+    return isLessThan(a1, a2) ? a1 : a2;
+  }
+
+  /**
+   * A function that returns the greater of its two arguments.
+   */
+  public final F<A, F<A, A>> max = curry(new F2<A, A, A>() {
+    public A f(final A a, final A a1) {
+      return max(a, a1);
+    }
+  });
+
+  /**
+   * A function that returns the lesser of its two arguments.
+   */
+  public final F<A, F<A, A>> min = curry(new F2<A, A, A>() {
+    public A f(final A a, final A a1) {
+      return min(a, a1);
+    }
+  });
+
+  /**
+   * Returns an order instance that uses the given equality test and ordering function.
+   *
+   * @param f The order function.
+   * @return An order instance.
+   */
+  public static <A> Ord<A> ord(final F<A, F<A, Ordering>> f) {
+    return new Ord<A>(f);
+  }
+
+  /**
+   * An order instance for the <code>boolean</code> type.
+   */
+  public static final Ord<Boolean> booleanOrd = new Ord<Boolean>(
+      new F<Boolean, F<Boolean, Ordering>>() {
+        public F<Boolean, Ordering> f(final Boolean a1) {
+          return new F<Boolean, Ordering>() {
+            public Ordering f(final Boolean a2) {
+              final int x = a1.compareTo(a2);
+              return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
+            }
+          };
+        }
+      });
+
+  /**
+   * An order instance for the <code>byte</code> type.
+   */
+  public static final Ord<Byte> byteOrd = new Ord<Byte>(
+      new F<Byte, F<Byte, Ordering>>() {
+        public F<Byte, Ordering> f(final Byte a1) {
+          return new F<Byte, Ordering>() {
+            public Ordering f(final Byte a2) {
+              final int x = a1.compareTo(a2);
+              return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
+            }
+          };
+        }
+      });
+
+  /**
+   * An order instance for the <code>char</code> type.
+   */
+  public static final Ord<Character> charOrd = new Ord<Character>(
+      new F<Character, F<Character, Ordering>>() {
+        public F<Character, Ordering> f(final Character a1) {
+          return new F<Character, Ordering>() {
+            public Ordering f(final Character a2) {
+              final int x = a1.compareTo(a2);
+              return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
+            }
+          };
+        }
+      });
+
+  /**
+   * An order instance for the <code>double</code> type.
+   */
+  public static final Ord<Double> doubleOrd = new Ord<Double>(
+      new F<Double, F<Double, Ordering>>() {
+        public F<Double, Ordering> f(final Double a1) {
+          return new F<Double, Ordering>() {
+            public Ordering f(final Double a2) {
+              final int x = a1.compareTo(a2);
+              return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
+            }
+          };
+        }
+      });
+
+  /**
+   * An order instance for the <code>float</code> type.
+   */
+  public static final Ord<Float> floatOrd = new Ord<Float>(
+      new F<Float, F<Float, Ordering>>() {
+        public F<Float, Ordering> f(final Float a1) {
+          return new F<Float, Ordering>() {
+            public Ordering f(final Float a2) {
+              final int x = a1.compareTo(a2);
+              return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
+            }
+          };
+        }
+      });
+
+  /**
+   * An order instance for the <code>int</code> type.
+   */
+  public static final Ord<Integer> intOrd = new Ord<Integer>(
+      new F<Integer, F<Integer, Ordering>>() {
+        public F<Integer, Ordering> f(final Integer a1) {
+          return new F<Integer, Ordering>() {
+            public Ordering f(final Integer a2) {
+              final int x = a1.compareTo(a2);
+              return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
+            }
+          };
+        }
+      });
+
+  /**
+   * An order instance for the <code>BigInteger</code> type.
+   */
+  public static final Ord<BigInteger> bigintOrd = new Ord<BigInteger>(
+      new F<BigInteger, F<BigInteger, Ordering>>() {
+        public F<BigInteger, Ordering> f(final BigInteger a1) {
+          return new F<BigInteger, Ordering>() {
+            public Ordering f(final BigInteger a2) {
+              final int x = a1.compareTo(a2);
+              return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
+            }
+          };
+        }
+      });
+
+  /**
+   * An order instance for the <code>BigDecimal</code> type.
+   */
+  public static final Ord<BigDecimal> bigdecimalOrd = new Ord<BigDecimal>(
+      new F<BigDecimal, F<BigDecimal, Ordering>>() {
+        public F<BigDecimal, Ordering> f(final BigDecimal a1) {
+          return new F<BigDecimal, Ordering>() {
+            public Ordering f(final BigDecimal a2) {
+              final int x = a1.compareTo(a2);
+              return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
+            }
+          };
+        }
+      });
+
+  /**
+   * An order instance for the <code>long</code> type.
+   */
+  public static final Ord<Long> longOrd = new Ord<Long>(
+      new F<Long, F<Long, Ordering>>() {
+        public F<Long, Ordering> f(final Long a1) {
+          return new F<Long, Ordering>() {
+            public Ordering f(final Long a2) {
+              final int x = a1.compareTo(a2);
+              return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
+            }
+          };
+        }
+      });
+
+  /**
+   * An order instance for the <code>short</code> type.
+   */
+  public static final Ord<Short> shortOrd = new Ord<Short>(
+      new F<Short, F<Short, Ordering>>() {
+        public F<Short, Ordering> f(final Short a1) {
+          return new F<Short, Ordering>() {
+            public Ordering f(final Short a2) {
+              final int x = a1.compareTo(a2);
+              return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
+            }
+          };
+        }
+      });
+
+  /**
+   * An order instance for the {@link Ordering} type.
+   */
+  public static final Ord<Ordering> orderingOrd = new Ord<Ordering>(curry(new F2<Ordering, Ordering, Ordering>() {
+    public Ordering f(final Ordering o1, final Ordering o2) {
+      return o1 == o2 ?
+             Ordering.EQ :
+             o1 == Ordering.LT ?
+             Ordering.LT :
+             o2 == Ordering.LT ?
+             Ordering.GT :
+             o1 == Ordering.EQ ?
+             Ordering.LT :
+             Ordering.GT;
+    }
+  }));
+
+  /**
+   * An order instance for the {@link String} type.
+   */
+  public static final Ord<String> stringOrd = new Ord<String>(
+      new F<String, F<String, Ordering>>() {
+        public F<String, Ordering> f(final String a1) {
+          return new F<String, Ordering>() {
+            public Ordering f(final String a2) {
+              final int x = a1.compareTo(a2);
+              return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
+            }
+          };
+        }
+      });
+
+  /**
+   * An order instance for the {@link StringBuffer} type.
+   */
+  public static final Ord<StringBuffer> stringBufferOrd =
+      new Ord<StringBuffer>(new F<StringBuffer, F<StringBuffer, Ordering>>() {
+        public F<StringBuffer, Ordering> f(final StringBuffer a1) {
+          return new F<StringBuffer, Ordering>() {
+            public Ordering f(final StringBuffer a2) {
+              return stringOrd.compare(a1.toString(), a2.toString());
+            }
+          };
+        }
+      });
+
+  /**
+   * An order instance for the {@link StringBuffer} type.
+   */
+  public static final Ord<StringBuilder> stringBuilderOrd =
+      new Ord<StringBuilder>(new F<StringBuilder, F<StringBuilder, Ordering>>() {
+        public F<StringBuilder, Ordering> f(final StringBuilder a1) {
+          return new F<StringBuilder, Ordering>() {
+            public Ordering f(final StringBuilder a2) {
+              return stringOrd.compare(a1.toString(), a2.toString());
+            }
+          };
+        }
+      });
+
+  /**
+   * An order instance for the {@link Option} type.
+   *
+   * @param oa Order across the element of the option.
+   * @return An order instance for the {@link Option} type.
+   */
+  public static <A> Ord<Option<A>> optionOrd(final Ord<A> oa) {
+    return new Ord<Option<A>>(new F<Option<A>, F<Option<A>, Ordering>>() {
+      public F<Option<A>, Ordering> f(final Option<A> o1) {
+        return new F<Option<A>, Ordering>() {
+          public Ordering f(final Option<A> o2) {
+            return o1.isNone() ?
+                   o2.isNone() ?
+                   Ordering.EQ :
+                   Ordering.LT :
+                   o2.isNone() ?
+                   Ordering.GT :
+                   oa.f.f(o1.some()).f(o2.some());
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An order instance for the {@link Either} type.
+   *
+   * @param oa Order across the left side of {@link Either}.
+   * @param ob Order across the right side of {@link Either}.
+   * @return An order instance for the {@link Either} type.
+   */
+  public static <A, B> Ord<Either<A, B>> eitherOrd(final Ord<A> oa, final Ord<B> ob) {
+    return new Ord<Either<A, B>>(new F<Either<A, B>, F<Either<A, B>, Ordering>>() {
+      public F<Either<A, B>, Ordering> f(final Either<A, B> e1) {
+        return new F<Either<A, B>, Ordering>() {
+          public Ordering f(final Either<A, B> e2) {
+            return e1.isLeft() ?
+                   e2.isLeft() ?
+                   oa.f.f(e1.left().value()).f(e2.left().value()) :
+                   Ordering.LT :
+                   e2.isLeft() ?
+                   Ordering.GT :
+                   ob.f.f(e1.right().value()).f(e2.right().value());
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An order instance for the {@link Validation} type.
+   *
+   * @param oa Order across the failing side of {@link Validation}.
+   * @param ob Order across the succeeding side of {@link Validation}.
+   * @return An order instance for the {@link Validation} type.
+   */
+  public static <A, B> Ord<Validation<A, B>> validationOrd(final Ord<A> oa, final Ord<B> ob) {
+    return eitherOrd(oa, ob).comap(Validation.<A, B>either());
+  }
+
+  /**
+   * An order instance for the {@link List} type.
+   *
+   * @param oa Order across the elements of the list.
+   * @return An order instance for the {@link List} type.
+   */
+  public static <A> Ord<List<A>> listOrd(final Ord<A> oa) {
+    return new Ord<List<A>>(new F<List<A>, F<List<A>, Ordering>>() {
+      public F<List<A>, Ordering> f(final List<A> l1) {
+        return new F<List<A>, Ordering>() {
+          public Ordering f(final List<A> l2) {
+            if (l1.isEmpty())
+              return l2.isEmpty() ? Ordering.EQ : Ordering.LT;
+            else if (l2.isEmpty())
+              return l1.isEmpty() ? Ordering.EQ : Ordering.GT;
+            else {
+              final Ordering c = oa.compare(l1.head(), l2.head());
+              return c == Ordering.EQ ? listOrd(oa).f.f(l1.tail()).f(l2.tail()) : c;
+            }
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An order instance for the {@link NonEmptyList} type.
+   *
+   * @param oa Order across the elements of the non-empty list.
+   * @return An order instance for the {@link NonEmptyList} type.
+   */
+  public static <A> Ord<NonEmptyList<A>> nonEmptyListOrd(final Ord<A> oa) {
+    return listOrd(oa).comap(NonEmptyList.<A>toList_());
+  }
+
+  /**
+   * An order instance for the {@link Stream} type.
+   *
+   * @param oa Order across the elements of the stream.
+   * @return An order instance for the {@link Stream} type.
+   */
+  public static <A> Ord<Stream<A>> streamOrd(final Ord<A> oa) {
+    return new Ord<Stream<A>>(new F<Stream<A>, F<Stream<A>, Ordering>>() {
+      public F<Stream<A>, Ordering> f(final Stream<A> s1) {
+        return new F<Stream<A>, Ordering>() {
+          public Ordering f(final Stream<A> s2) {
+            if (s1.isEmpty())
+              return s2.isEmpty() ? Ordering.EQ : Ordering.LT;
+            else if (s2.isEmpty())
+              return s1.isEmpty() ? Ordering.EQ : Ordering.GT;
+            else {
+              final Ordering c = oa.compare(s1.head(), s2.head());
+              return c == Ordering.EQ ? streamOrd(oa).f.f(s1.tail()._1()).f(s2.tail()._1()) : c;
+            }
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An order instance for the {@link Array} type.
+   *
+   * @param oa Order across the elements of the array.
+   * @return An order instance for the {@link Array} type.
+   */
+  public static <A> Ord<Array<A>> arrayOrd(final Ord<A> oa) {
+    return new Ord<Array<A>>(new F<Array<A>, F<Array<A>, Ordering>>() {
+      public F<Array<A>, Ordering> f(final Array<A> a1) {
+        return new F<Array<A>, Ordering>() {
+          public Ordering f(final Array<A> a2) {
+            int i = 0;
+            //noinspection ForLoopWithMissingComponent
+            for (; i < a1.length() && i < a2.length(); i++) {
+              final Ordering c = oa.compare(a1.get(i), a2.get(i));
+              if (c == Ordering.GT || c == Ordering.LT)
+                return c;
+            }
+            return i == a1.length() ?
+                   i == a2.length() ?
+                   Ordering.EQ :
+                   Ordering.LT :
+                   i == a1.length() ?
+                   Ordering.EQ :
+                   Ordering.GT;
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An order instance for the {@link Set} type.
+   *
+   * @param oa Order across the elements of the set.
+   * @return An order instance for the {@link Set} type.
+   */
+  public static <A> Ord<Set<A>> setOrd(final Ord<A> oa) {
+    return streamOrd(oa).comap(new F<Set<A>, Stream<A>>() {
+      public Stream<A> f(final Set<A> as) {
+        return as.toStream();
+      }
+    });
+  }
+
+  /**
+   * An order instance for the {@link Unit} type.
+   */
+  public static final Ord<Unit> unitOrd = ord(curry(new F2<Unit, Unit, Ordering>() {
+    public Ordering f(final Unit u1, final Unit u2) {
+      return Ordering.EQ;
+    }
+  }));
+
+  /**
+   * An order instance for a product-1.
+   *
+   * @param oa Order across the produced type.
+   * @return An order instance for a product-1.
+   */
+  public static <A> Ord<P1<A>> p1Ord(final Ord<A> oa) {
+    return oa.comap(P1.<A>__1());
+  }
+
+
+  /**
+   * An order instance for a product-2, with the first factor considered most significant.
+   *
+   * @param oa An order instance for the first factor.
+   * @param ob An order instance for the second factor.
+   * @return An order instance for a product-2, with the first factor considered most significant.
+   */
+  public static <A, B> Ord<P2<A, B>> p2Ord(final Ord<A> oa, final Ord<B> ob) {
+    return ord(curry(new F2<P2<A, B>, P2<A, B>, Ordering>() {
+      public Ordering f(final P2<A, B> a, final P2<A, B> b) {
+        return oa.eq(a._1(), b._1()) ? ob.compare(a._2(), b._2()) : oa.compare(a._1(), b._1());
+      }
+    }));
+  }
+
+  /**
+   * An order instance for a product-3, with the first factor considered most significant.
+   *
+   * @param oa An order instance for the first factor.
+   * @param ob An order instance for the second factor.
+   * @param oc An order instance for the third factor.
+   * @return An order instance for a product-3, with the first factor considered most significant.
+   */
+  public static <A, B, C> Ord<P3<A, B, C>> p3Ord(final Ord<A> oa, final Ord<B> ob, final Ord<C> oc) {
+    return ord(curry(new F2<P3<A, B, C>, P3<A, B, C>, Ordering>() {
+      public Ordering f(final P3<A, B, C> a, final P3<A, B, C> b) {
+        return oa.eq(a._1(), b._1()) ?
+               p2Ord(ob, oc).compare(P.p(a._2(), a._3()), P.p(b._2(), b._3()))
+                                     : oa.compare(a._1(), b._1());
+      }
+    }));
+  }
+
+  /**
+   * An order instance for the <code>Natural</code> type.
+   */
+  public static final Ord<Natural> naturalOrd = bigintOrd.comap(Natural.bigIntegerValue);
+
+
+  /**
+   * An order instance for the <code>Comparable</code> interface.
+   *
+   * @return An order instance for the <code>Comparable</code> interface.
+   */
+  public static <A extends Comparable<A>> Ord<A> comparableOrd() {
+    return ord(new F<A, F<A, Ordering>>() {
+      public F<A, Ordering> f(final A a1) {
+        return new F<A, Ordering>() {
+          public Ordering f(final A a2) {
+            return Ordering.fromInt(a1.compareTo(a2));
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An order instance that uses {@link Object#hashCode()} for computing the order and equality,
+   * thus objects returning the same hashCode are considered to be equals (check {@link #hashEqualsOrd()}
+   * for an additional check on {@link Object#equals(Object)}).
+   *
+   * @return An order instance that is based on {@link Object#hashCode()}.
+   * @see #hashEqualsOrd()
+   */
+  public static <A> Ord<A> hashOrd() {
+    return Ord.<A> ord(new F<A, F<A, Ordering>>() {
+      @Override
+      public F<A, Ordering> f(final A a) {
+        return new F<A, Ordering>() {
+          @Override
+          public Ordering f(final A a2) {
+            final int x = a.hashCode() - a2.hashCode();
+            return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
+          }
+        };
+      }
+    });
+  }
+
+  /**
+   * An order instance that uses {@link Object#hashCode()} and {@link Object#equals} for computing
+   * the order and equality. First the hashCode is compared, if this is equal, objects are compared
+   * using {@link Object#equals}.
+   *
+   * @return An order instance that is based on {@link Object#hashCode()} and {@link Object#equals}.
+   */
+  public static <A> Ord<A> hashEqualsOrd() {
+    return Ord.<A> ord(new F<A, F<A, Ordering>>() {
+      @Override
+      public F<A, Ordering> f(final A a) {
+        return new F<A, Ordering>() {
+          @Override
+          public Ordering f(final A a2) {
+            final int x = a.hashCode() - a2.hashCode();
+            return x < 0 ? Ordering.LT : x == 0 && a.equals(a2) ? Ordering.EQ : Ordering.GT;
+          }
+        };
+      }
+    });
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/Ordering.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,29 @@
+package fj;
+
+/**
+ * The comparison of two instances of a type may have one of three orderings; less than, equal or
+ * greater than.
+ *
+ * @version %build.number%
+ */
+public enum Ordering {
+  /**
+   * Less than.
+   */
+  LT,
+
+  /**
+   * Equal.
+   */
+  EQ,
+
+  /**
+   * Greater than.
+   */
+  GT;
+
+  public int toInt() { return ordinal() - 1 ; }
+  public static Ordering fromInt(int cmp) {
+    return cmp == 0 ? EQ : cmp > 0 ? GT : LT;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/P.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,863 @@
+package fj;
+
+import static fj.Unit.unit;
+
+/**
+ * Functions across products.
+ *
+ * @version %build.number%
+ */
+public final class P {
+  private P() {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * A function that puts an element in a product-1.
+   *
+   * @return A function that puts an element in a product-1.
+   */
+  public static <A> F<A, P1<A>> p1() {
+    return new F<A, P1<A>>() {
+      public P1<A> f(final A a) {
+        return p(a);
+      }
+    };
+  }
+
+  /**
+   * A function that puts an element in a product-1.
+   *
+   * @param a The element.
+   * @return The product-1.
+   */
+  public static <A> P1<A> p(final A a) {
+    return new P1<A>() {
+      public A _1() {
+        return a;
+      }
+    };
+  }
+
+
+    public static <A> P1<A> lazy(final P1<A> pa) {
+        return pa;
+    }
+
+    public static <A, B> P2<A, B> lazy(final P1<A> pa, final P1<B> pb) {
+        return new P2<A, B>() {
+            @Override
+            public A _1() {
+                return pa._1();
+            }
+            @Override
+            public B _2() {
+                return pb._1();
+            }
+        };
+    }
+
+    public static <A, B, C> P3<A, B, C> lazy(final P1<A> pa, final P1<B> pb, final P1<C> pc) {
+        return new P3<A, B, C>() {
+            @Override
+            public A _1() {
+                return pa._1();
+            }
+            @Override
+            public B _2() {
+                return pb._1();
+            }
+            @Override
+            public C _3() {
+                return pc._1();
+            }
+        };
+    }
+
+    public static <A, B, C, D> P4<A, B, C, D> lazy(final P1<A> pa, final P1<B> pb, final P1<C> pc, final P1<D> pd) {
+        return new P4<A, B, C, D>() {
+            @Override
+            public A _1() {
+                return pa._1();
+            }
+            @Override
+            public B _2() {
+                return pb._1();
+            }
+            @Override
+            public C _3() {
+                return pc._1();
+            }
+
+            @Override
+            public D _4() {
+                return pd._1();
+            }
+        };
+    }
+
+    public static <A, B, C, D, E> P5<A, B, C, D, E> lazy(final P1<A> pa, final P1<B> pb, final P1<C> pc, final P1<D> pd, P1<E> pe) {
+        return new P5<A, B, C, D, E>() {
+            @Override
+            public A _1() {
+                return pa._1();
+            }
+            @Override
+            public B _2() {
+                return pb._1();
+            }
+            @Override
+            public C _3() {
+                return pc._1();
+            }
+
+            @Override
+            public D _4() {
+                return pd._1();
+            }
+
+            @Override
+            public E _5() {
+                return pe._1();
+            }
+        };
+    }
+
+    public static <A, B, C, D, E, F> P6<A, B, C, D, E, F> lazy(final P1<A> pa, final P1<B> pb, final P1<C> pc, final P1<D> pd, P1<E> pe, P1<F> pf) {
+        return new P6<A, B, C, D, E, F>() {
+            @Override
+            public A _1() {
+                return pa._1();
+            }
+            @Override
+            public B _2() {
+                return pb._1();
+            }
+            @Override
+            public C _3() {
+                return pc._1();
+            }
+
+            @Override
+            public D _4() {
+                return pd._1();
+            }
+
+            @Override
+            public E _5() {
+                return pe._1();
+            }
+
+            @Override
+            public F _6() {
+                return pf._1();
+            }
+        };
+    }
+
+    public static <A, B, C, D, E, F, G> P7<A, B, C, D, E, F, G> lazy(final P1<A> pa, final P1<B> pb, final P1<C> pc, final P1<D> pd, P1<E> pe, P1<F> pf, P1<G> pg) {
+        return new P7<A, B, C, D, E, F, G>() {
+            @Override
+            public A _1() {
+                return pa._1();
+            }
+            @Override
+            public B _2() {
+                return pb._1();
+            }
+            @Override
+            public C _3() {
+                return pc._1();
+            }
+
+            @Override
+            public D _4() {
+                return pd._1();
+            }
+
+            @Override
+            public E _5() {
+                return pe._1();
+            }
+
+            @Override
+            public F _6() {
+                return pf._1();
+            }
+
+            @Override
+            public G _7() {
+                return pg._1();
+            }
+        };
+    }
+
+    public static <A, B, C, D, E, F, G, H> P8<A, B, C, D, E, F, G, H> lazy(final P1<A> pa, final P1<B> pb, final P1<C> pc, final P1<D> pd, P1<E> pe, P1<F> pf, P1<G> pg, P1<H> ph) {
+        return new P8<A, B, C, D, E, F, G, H>() {
+            @Override
+            public A _1() {
+                return pa._1();
+            }
+            @Override
+            public B _2() {
+                return pb._1();
+            }
+            @Override
+            public C _3() {
+                return pc._1();
+            }
+
+            @Override
+            public D _4() {
+                return pd._1();
+            }
+
+            @Override
+            public E _5() {
+                return pe._1();
+            }
+
+            @Override
+            public F _6() {
+                return pf._1();
+            }
+
+            @Override
+            public G _7() {
+                return pg._1();
+            }
+
+            @Override
+            public H _8() {
+                return ph._1();
+            }
+        };
+    }
+
+    /**
+   * A function that puts an element in a product-2.
+   *
+   * @return A function that puts an element in a product-2.
+   */
+  public static <A, B> F<A, F<B, P2<A, B>>> p2() {
+    return new F<A, F<B, P2<A, B>>>() {
+      public F<B, P2<A, B>> f(final A a) {
+        return new F<B, P2<A, B>>() {
+          public P2<A, B> f(final B b) {
+            return p(a, b);
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * A function that puts elements in a product-2.
+   *
+   * @param a An element.
+   * @param b An element.
+   * @return The product-2.
+   */
+  public static <A, B> P2<A, B> p(final A a, final B b) {
+    return new P2<A, B>() {
+      public A _1() {
+        return a;
+      }
+
+      public B _2() {
+        return b;
+      }
+    };
+  }
+
+  /**
+   * A function that puts an element in a product-3.
+   *
+   * @return A function that puts an element in a product-3.
+   */
+  public static <A, B, C> F<A, F<B, F<C, P3<A, B, C>>>> p3() {
+    return new F<A, F<B, F<C, P3<A, B, C>>>>() {
+      public F<B, F<C, P3<A, B, C>>> f(final A a) {
+        return new F<B, F<C, P3<A, B, C>>>() {
+          public F<C, P3<A, B, C>> f(final B b) {
+            return new F<C, P3<A, B, C>>() {
+              public P3<A, B, C> f(final C c) {
+                return p(a, b, c);
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * A function that puts elements in a product-3.
+   *
+   * @param a An element.
+   * @param b An element.
+   * @param c An element.
+   * @return The product-3.
+   */
+  public static <A, B, C> P3<A, B, C> p(final A a, final B b, final C c) {
+    return new P3<A, B, C>() {
+      public A _1() {
+        return a;
+      }
+
+      public B _2() {
+        return b;
+      }
+
+      public C _3() {
+        return c;
+      }
+    };
+  }
+
+  /**
+   * A function that puts an element in a product-4.
+   *
+   * @return A function that puts an element in a product-4.
+   */
+  public static <A, B, C, D> F<A, F<B, F<C, F<D, P4<A, B, C, D>>>>> p4() {
+    return new F<A, F<B, F<C, F<D, P4<A, B, C, D>>>>>() {
+      public F<B, F<C, F<D, P4<A, B, C, D>>>> f(final A a) {
+        return new F<B, F<C, F<D, P4<A, B, C, D>>>>() {
+          public F<C, F<D, P4<A, B, C, D>>> f(final B b) {
+            return new F<C, F<D, P4<A, B, C, D>>>() {
+              public F<D, P4<A, B, C, D>> f(final C c) {
+                return new F<D, P4<A, B, C, D>>() {
+                  public P4<A, B, C, D> f(final D d) {
+                    return p(a, b, c, d);
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * A function that puts elements in a product-4.
+   *
+   * @param a An element.
+   * @param b An element.
+   * @param c An element.
+   * @param d An element.
+   * @return The product-4.
+   */
+  public static <A, B, C, D> P4<A, B, C, D> p(final A a, final B b, final C c, final D d) {
+    return new P4<A, B, C, D>() {
+      public A _1() {
+        return a;
+      }
+
+      public B _2() {
+        return b;
+      }
+
+      public C _3() {
+        return c;
+      }
+
+      public D _4() {
+        return d;
+      }
+    };
+  }
+
+  /**
+   * A function that puts an element in a product-5.
+   *
+   * @return A function that puts an element in a product-5.
+   */
+  public static <A, B, C, D, E> F<A, F<B, F<C, F<D, F<E, P5<A, B, C, D, E>>>>>> p5() {
+    return new F<A, F<B, F<C, F<D, F<E, P5<A, B, C, D, E>>>>>>() {
+      public F<B, F<C, F<D, F<E, P5<A, B, C, D, E>>>>> f(final A a) {
+        return new F<B, F<C, F<D, F<E, P5<A, B, C, D, E>>>>>() {
+          public F<C, F<D, F<E, P5<A, B, C, D, E>>>> f(final B b) {
+            return new F<C, F<D, F<E, P5<A, B, C, D, E>>>>() {
+              public F<D, F<E, P5<A, B, C, D, E>>> f(final C c) {
+                return new F<D, F<E, P5<A, B, C, D, E>>>() {
+                  public F<E, P5<A, B, C, D, E>> f(final D d) {
+                    return new F<E, P5<A, B, C, D, E>>() {
+                      public P5<A, B, C, D, E> f(final E e) {
+                        return p(a, b, c, d, e);
+                      }
+                    };
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * A function that puts elements in a product-5.
+   *
+   * @param a An element.
+   * @param b An element.
+   * @param c An element.
+   * @param d An element.
+   * @param e An element.
+   * @return The product-5.
+   */
+  public static <A, B, C, D, E> P5<A, B, C, D, E> p(final A a, final B b, final C c, final D d, final E e) {
+    return new P5<A, B, C, D, E>() {
+      public A _1() {
+        return a;
+      }
+
+      public B _2() {
+        return b;
+      }
+
+      public C _3() {
+        return c;
+      }
+
+      public D _4() {
+        return d;
+      }
+
+      public E _5() {
+        return e;
+      }
+    };
+  }
+
+  /**
+   * A function that puts an element in a product-6.
+   *
+   * @return A function that puts an element in a product-6.
+   */
+  public static <A, B, C, D, E, F$> F<A, F<B, F<C, F<D, F<E, F<F$, P6<A, B, C, D, E, F$>>>>>>> p6() {
+    return new F<A, F<B, F<C, F<D, F<E, F<F$, P6<A, B, C, D, E, F$>>>>>>>() {
+      public F<B, F<C, F<D, F<E, F<F$, P6<A, B, C, D, E, F$>>>>>> f(final A a) {
+        return new F<B, F<C, F<D, F<E, F<F$, P6<A, B, C, D, E, F$>>>>>>() {
+          public F<C, F<D, F<E, F<F$, P6<A, B, C, D, E, F$>>>>> f(final B b) {
+            return new F<C, F<D, F<E, F<F$, P6<A, B, C, D, E, F$>>>>>() {
+              public F<D, F<E, F<F$, P6<A, B, C, D, E, F$>>>> f(final C c) {
+                return new F<D, F<E, F<F$, P6<A, B, C, D, E, F$>>>>() {
+                  public F<E, F<F$, P6<A, B, C, D, E, F$>>> f(final D d) {
+                    return new F<E, F<F$, P6<A, B, C, D, E, F$>>>() {
+                      public F<F$, P6<A, B, C, D, E, F$>> f(final E e) {
+                        return new F<F$, P6<A, B, C, D, E, F$>>() {
+                          public P6<A, B, C, D, E, F$> f(final F$ f) {
+                            return p(a, b, c, d, e, f);
+                          }
+                        };
+                      }
+                    };
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * A function that puts elements in a product-6.
+   *
+   * @param a An element.
+   * @param b An element.
+   * @param c An element.
+   * @param d An element.
+   * @param e An element.
+   * @param f An element.
+   * @return The product-6.
+   */
+  public static <A, B, C, D, E, F$> P6<A, B, C, D, E, F$> p(final A a, final B b, final C c, final D d, final E e, final F$ f) {
+    return new P6<A, B, C, D, E, F$>() {
+      public A _1() {
+        return a;
+      }
+
+      public B _2() {
+        return b;
+      }
+
+      public C _3() {
+        return c;
+      }
+
+      public D _4() {
+        return d;
+      }
+
+      public E _5() {
+        return e;
+      }
+
+      public F$ _6() {
+        return f;
+      }
+    };
+  }
+
+  /**
+   * A function that puts an element in a product-7.
+   *
+   * @return A function that puts an element in a product-7.
+   */
+  public static <A, B, C, D, E, F$, G> F<A, F<B, F<C, F<D, F<E, F<F$, F<G, P7<A, B, C, D, E, F$, G>>>>>>>> p7() {
+    return new F<A, F<B, F<C, F<D, F<E, F<F$, F<G, P7<A, B, C, D, E, F$, G>>>>>>>>() {
+      public F<B, F<C, F<D, F<E, F<F$, F<G, P7<A, B, C, D, E, F$, G>>>>>>> f(final A a) {
+        return new F<B, F<C, F<D, F<E, F<F$, F<G, P7<A, B, C, D, E, F$, G>>>>>>>() {
+          public F<C, F<D, F<E, F<F$, F<G, P7<A, B, C, D, E, F$, G>>>>>> f(final B b) {
+            return new F<C, F<D, F<E, F<F$, F<G, P7<A, B, C, D, E, F$, G>>>>>>() {
+              public F<D, F<E, F<F$, F<G, P7<A, B, C, D, E, F$, G>>>>> f(final C c) {
+                return new F<D, F<E, F<F$, F<G, P7<A, B, C, D, E, F$, G>>>>>() {
+                  public F<E, F<F$, F<G, P7<A, B, C, D, E, F$, G>>>> f(final D d) {
+                    return new F<E, F<F$, F<G, P7<A, B, C, D, E, F$, G>>>>() {
+                      public F<F$, F<G, P7<A, B, C, D, E, F$, G>>> f(final E e) {
+                        return new F<F$, F<G, P7<A, B, C, D, E, F$, G>>>() {
+                          public F<G, P7<A, B, C, D, E, F$, G>> f(final F$ f) {
+                            return new F<G, P7<A, B, C, D, E, F$, G>>() {
+                              public P7<A, B, C, D, E, F$, G> f(final G g) {
+                                return p(a, b, c, d, e, f, g);
+                              }
+                            };
+                          }
+                        };
+                      }
+                    };
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+  
+  /**
+   * A function that puts elements in a product-7.
+   *
+   * @param a An element.
+   * @param b An element.
+   * @param c An element.
+   * @param d An element.
+   * @param e An element.
+   * @param f An element.
+   * @param g An element.
+   * @return The product-7.
+   */
+  public static <A, B, C, D, E, F$, G> P7<A, B, C, D, E, F$, G> p(final A a, final B b, final C c, final D d, final E e, final F$ f, final G g) {
+    return new P7<A, B, C, D, E, F$, G>() {
+      public A _1() {
+        return a;
+      }
+
+      public B _2() {
+        return b;
+      }
+
+      public C _3() {
+        return c;
+      }
+
+      public D _4() {
+        return d;
+      }
+
+      public E _5() {
+        return e;
+      }
+
+      public F$ _6() {
+        return f;
+      }
+
+      public G _7() {
+        return g;
+      }
+    };
+  }
+
+  /**
+   * A function that puts an element in a product-8.
+   *
+   * @return A function that puts an element in a product-8.
+   */
+  public static <A, B, C, D, E, F$, G, H> F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, P8<A, B, C, D, E, F$, G, H>>>>>>>>> p8() {
+    return new F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, P8<A, B, C, D, E, F$, G, H>>>>>>>>>() {
+      public F<B, F<C, F<D, F<E, F<F$, F<G, F<H, P8<A, B, C, D, E, F$, G, H>>>>>>>> f(final A a) {
+        return new F<B, F<C, F<D, F<E, F<F$, F<G, F<H, P8<A, B, C, D, E, F$, G, H>>>>>>>>() {
+          public F<C, F<D, F<E, F<F$, F<G, F<H, P8<A, B, C, D, E, F$, G, H>>>>>>> f(final B b) {
+            return new F<C, F<D, F<E, F<F$, F<G, F<H, P8<A, B, C, D, E, F$, G, H>>>>>>>() {
+              public F<D, F<E, F<F$, F<G, F<H, P8<A, B, C, D, E, F$, G, H>>>>>> f(final C c) {
+                return new F<D, F<E, F<F$, F<G, F<H, P8<A, B, C, D, E, F$, G, H>>>>>>() {
+                  public F<E, F<F$, F<G, F<H, P8<A, B, C, D, E, F$, G, H>>>>> f(final D d) {
+                    return new F<E, F<F$, F<G, F<H, P8<A, B, C, D, E, F$, G, H>>>>>() {
+                      public F<F$, F<G, F<H, P8<A, B, C, D, E, F$, G, H>>>> f(final E e) {
+                        return new F<F$, F<G, F<H, P8<A, B, C, D, E, F$, G, H>>>>() {
+                          public F<G, F<H, P8<A, B, C, D, E, F$, G, H>>> f(final F$ f) {
+                            return new F<G, F<H, P8<A, B, C, D, E, F$, G, H>>>() {
+                              public F<H, P8<A, B, C, D, E, F$, G, H>> f(final G g) {
+                                return new F<H, P8<A, B, C, D, E, F$, G, H>>() {
+                                  public P8<A, B, C, D, E, F$, G, H> f(final H h) {
+                                    return p(a, b, c, d, e, f, g, h);
+                                  }
+                                };
+                              }
+                            };
+                          }
+                        };
+                      }
+                    };
+                  }
+                };
+              }
+            };
+          }
+        };
+      }
+    };
+  }
+
+  /**
+   * A function that puts elements in a product-8.
+   *
+   * @param a An element.
+   * @param b An element.
+   * @param c An element.
+   * @param d An element.
+   * @param e An element.
+   * @param f An element.
+   * @param g An element.
+   * @param h An element.
+   * @return The product-8.
+   */
+  public static <A, B, C, D, E, F$, G, H> P8<A, B, C, D, E, F$, G, H> p(final A a, final B b, final C c, final D d, final E e, final F$ f, final G g, final H h) {
+    return new P8<A, B, C, D, E, F$, G, H>() {
+      public A _1() {
+        return a;
+      }
+
+      public B _2() {
+        return b;
+      }
+
+      public C _3() {
+        return c;
+      }
+
+      public D _4() {
+        return d;
+      }
+
+      public E _5() {
+        return e;
+      }
+
+      public F$ _6() {
+        return f;
+      }
+
+      public G _7() {
+        return g;
+      }
+
+      public H _8() {
+        return h;
+      }
+    };
+  }
+
+    public static <A> P1<A> lazy(F<Unit, A> f) {
+        return new P1<A>() {
+            @Override
+            public A _1() {
+                return f.f(unit());
+            }
+        };
+    }
+
+    public static <A, B> P2<A, B> lazy(F<Unit, A> fa, F<Unit, B> fb) {
+        return new P2<A, B>() {
+            @Override
+            public A _1() {
+                return fa.f(unit());
+            }
+            @Override
+            public B _2() {
+                return fb.f(unit());
+            }
+        };
+    }
+
+    public static <A, B, C> P3<A, B, C> lazy(F<Unit, A> fa, F<Unit, B> fb, F<Unit, C> fc) {
+        return new P3<A, B, C>() {
+            @Override
+            public A _1() {
+                return fa.f(unit());
+            }
+            @Override
+            public B _2() {
+                return fb.f(unit());
+            }
+            @Override
+            public C _3() {
+                return fc.f(unit());
+            }
+        };
+    }
+
+
+    public static <A, B, C, D> P4<A, B, C, D> lazy(F<Unit, A> fa, F<Unit, B> fb, F<Unit, C> fc, F<Unit, D> fd) {
+        return new P4<A, B, C, D>() {
+            @Override
+            public A _1() {
+                return fa.f(unit());
+            }
+            @Override
+            public B _2() {
+                return fb.f(unit());
+            }
+            @Override
+            public C _3() {
+                return fc.f(unit());
+            }
+            @Override
+            public D _4() {
+                return fd.f(unit());
+            }
+        };
+    }
+
+    public static <A, B, C, D, E> P5<A, B, C, D, E> lazy(F<Unit, A> fa, F<Unit, B> fb, F<Unit, C> fc, F<Unit, D> fd, F<Unit, E> fe) {
+        return new P5<A, B, C, D, E>() {
+            @Override
+            public A _1() {
+                return fa.f(unit());
+            }
+            @Override
+            public B _2() {
+                return fb.f(unit());
+            }
+            @Override
+            public C _3() {
+                return fc.f(unit());
+            }
+            @Override
+            public D _4() {
+                return fd.f(unit());
+            }
+            @Override
+            public E _5() {
+                return fe.f(unit());
+            }
+        };
+    }
+
+    public static <A, B, C, D, E, F$> P6<A, B, C, D, E, F$> lazy(F<Unit, A> fa, F<Unit, B> fb, F<Unit, C> fc, F<Unit, D> fd, F<Unit, E> fe, F<Unit, F$> ff) {
+        return new P6<A, B, C, D, E, F$>() {
+            @Override
+            public A _1() {
+                return fa.f(unit());
+            }
+            @Override
+            public B _2() {
+                return fb.f(unit());
+            }
+            @Override
+            public C _3() {
+                return fc.f(unit());
+            }
+            @Override
+            public D _4() {
+                return fd.f(unit());
+            }
+            @Override
+            public E _5() {
+                return fe.f(unit());
+            }
+            @Override
+            public F$ _6() {
+                return ff.f(unit());
+            }
+        };
+    }
+
+    public static <A, B, C, D, E, F$, G> P7<A, B, C, D, E, F$, G> lazy(F<Unit, A> fa, F<Unit, B> fb, F<Unit, C> fc, F<Unit, D> fd, F<Unit, E> fe, F<Unit, F$> ff, F<Unit, G> fg) {
+        return new P7<A, B, C, D, E, F$, G>() {
+            @Override
+            public A _1() {
+                return fa.f(unit());
+            }
+            @Override
+            public B _2() {
+                return fb.f(unit());
+            }
+            @Override
+            public C _3() {
+                return fc.f(unit());
+            }
+            @Override
+            public D _4() {
+                return fd.f(unit());
+            }
+            @Override
+            public E _5() {
+                return fe.f(unit());
+            }
+            @Override
+            public F$ _6() {
+                return ff.f(unit());
+            }
+            @Override
+            public G _7() {
+                return fg.f(unit());
+            }
+        };
+    }
+
+    public static <A, B, C, D, E, F$, G, H> P8<A, B, C, D, E, F$, G, H> lazy(F<Unit, A> fa, F<Unit, B> fb, F<Unit, C> fc, F<Unit, D> fd, F<Unit, E> fe, F<Unit, F$> ff, F<Unit, G> fg, F<Unit, H> fh) {
+        return new P8<A, B, C, D, E, F$, G, H>() {
+            @Override
+            public A _1() {
+                return fa.f(unit());
+            }
+            @Override
+            public B _2() {
+                return fb.f(unit());
+            }
+            @Override
+            public C _3() {
+                return fc.f(unit());
+            }
+            @Override
+            public D _4() {
+                return fd.f(unit());
+            }
+            @Override
+            public E _5() {
+                return fe.f(unit());
+            }
+            @Override
+            public F$ _6() {
+                return ff.f(unit());
+            }
+            @Override
+            public G _7() {
+                return fg.f(unit());
+            }
+            @Override
+            public H _8() {
+                return fh.f(unit());
+            }
+        };
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/P1.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,238 @@
+package fj;
+
+import java.lang.ref.SoftReference;
+
+import fj.data.Array;
+import fj.data.List;
+import fj.data.Stream;
+import fj.data.Validation;
+import fj.function.Try0;
+
+public abstract class P1<A> {
+
+    /**
+     * Access the first element of the product.
+     *
+     * @return The first element of the product.
+     */
+    public abstract A _1();
+
+    /**
+     * Returns a function that returns the first element of a product.
+     *
+     * @return A function that returns the first element of a product.
+     */
+    public static <A> F<P1<A>, A> __1() {
+        return new F<P1<A>, A>() {
+            public A f(final P1<A> p) {
+                return p._1();
+            }
+        };
+    }
+
+    /**
+     * Promote any function to a transformation between P1s.
+     *
+     * @param f A function to promote to a transformation between P1s.
+     * @return A function promoted to operate on P1s.
+     */
+    public static <A, B> F<P1<A>, P1<B>> fmap(final F<A, B> f) {
+        return new F<P1<A>, P1<B>>() {
+            public P1<B> f(final P1<A> a) {
+                return a.map(f);
+            }
+        };
+    }
+
+    /**
+     * Binds the given function to the value in a product-1 with a final join.
+     *
+     * @param f A function to apply to the value in a product-1.
+     * @return The result of applying the given function to the value of given product-1.
+     */
+    public <B> P1<B> bind(final F<A, P1<B>> f) {
+        P1<A> self = this;
+        return new P1<B>() {
+            public B _1() {
+                return f.f(self._1())._1();
+            }
+        };
+    }
+
+    /**
+     * Promotes the given function so that it returns its value in a P1.
+     *
+     * @param f A function to have its result wrapped in a P1.
+     * @return A function whose result is wrapped in a P1.
+     */
+    public static <A, B> F<A, P1<B>> curry(final F<A, B> f) {
+        return new F<A, P1<B>>() {
+            public P1<B> f(final A a) {
+                return new P1<B>() {
+                    public B _1() {
+                        return f.f(a);
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Performs function application within a P1 (applicative functor pattern).
+     *
+     * @param cf The P1 function to apply.
+     * @return A new P1 after applying the given P1 function to the first argument.
+     */
+    public <B> P1<B> apply(final P1<F<A, B>> cf) {
+        P1<A> self = this;
+        return cf.bind(new F<F<A, B>, P1<B>>() {
+            public P1<B> f(final F<A, B> f) {
+                return fmap(f).f(self);
+            }
+        });
+    }
+
+    /**
+     * Binds the given function to the values in the given P1s with a final join.
+     *
+     * @param cb A given P1 to bind the given function with.
+     * @param f  The function to apply to the values in the given P1s.
+     * @return A new P1 after performing the map, then final join.
+     */
+    public <B, C> P1<C> bind(final P1<B> cb, final F<A, F<B, C>> f) {
+        return cb.apply(fmap(f).f(this));
+    }
+
+    /**
+     * Joins a P1 of a P1 with a bind operation.
+     *
+     * @param a The P1 of a P1 to join.
+     * @return A new P1 that is the join of the given P1.
+     */
+    public static <A> P1<A> join(final P1<P1<A>> a) {
+        return a.bind(Function.<P1<A>>identity());
+    }
+
+    /**
+     * Promotes a function of arity-2 to a function on P1s.
+     *
+     * @param f The function to promote.
+     * @return A function of arity-2 promoted to map over P1s.
+     */
+    public static <A, B, C> F<P1<A>, F<P1<B>, P1<C>>> liftM2(final F<A, F<B, C>> f) {
+        return Function.curry(new F2<P1<A>, P1<B>, P1<C>>() {
+            public P1<C> f(final P1<A> pa, final P1<B> pb) {
+                return pa.bind(pb, f);
+            }
+        });
+    }
+
+    /**
+     * Turns a List of P1s into a single P1 of a List.
+     *
+     * @param as The list of P1s to transform.
+     * @return A single P1 for the given List.
+     */
+    public static <A> P1<List<A>> sequence(final List<P1<A>> as) {
+        return as.foldRight(liftM2(List.<A>cons()), P.p(List.<A>nil()));
+    }
+
+    /**
+     * A first-class version of the sequence method for lists of P1s.
+     *
+     * @return A function from a List of P1s to a single P1 of a List.
+     */
+    public static <A> F<List<P1<A>>, P1<List<A>>> sequenceList() {
+        return new F<List<P1<A>>, P1<List<A>>>() {
+            public P1<List<A>> f(final List<P1<A>> as) {
+                return sequence(as);
+            }
+        };
+    }
+
+    /**
+     * Turns a stream of P1s into a single P1 of a stream.
+     *
+     * @param as The stream of P1s to transform.
+     * @return A single P1 for the given stream.
+     */
+    public static <A> P1<Stream<A>> sequence(final Stream<P1<A>> as) {
+        return as.foldRight(liftM2(Stream.<A>cons()), P.p(Stream.<A>nil()));
+    }
+
+    /**
+     * Turns an array of P1s into a single P1 of an array.
+     *
+     * @param as The array of P1s to transform.
+     * @return A single P1 for the given array.
+     */
+    public static <A> P1<Array<A>> sequence(final Array<P1<A>> as) {
+        return new P1<Array<A>>() {
+            public Array<A> _1() {
+                return as.map(P1.<A>__1());
+            }
+        };
+    }
+
+    /**
+       * Map the element of the product.
+       *
+       * @param f The function to map with.
+       * @return A product with the given function applied.
+       */
+      public <X> P1<X> map(final F<A, X> f) {
+          final P1<A> self = this;
+        return new P1<X>() {
+          public X _1() {
+            return f.f(self._1());
+          }
+        };
+      }
+
+    /**
+       * Provides a memoising P1 that remembers its value.
+       *
+       * @return A P1 that calls this P1 once and remembers the value for subsequent calls.
+       */
+      public P1<A> memo() {
+          final P1<A> self = this;
+        return new P1<A>() {
+          private final Object latch = new Object();
+          @SuppressWarnings({"InstanceVariableMayNotBeInitialized"})
+          private volatile SoftReference<A> v;
+    
+          public A _1() {
+            A a = v != null ? v.get() : null;
+            if (a == null)
+              synchronized (latch) {
+                if (v == null || v.get() == null)
+                  a = self._1();
+                v = new SoftReference<A>(a);
+              }
+            return a;
+          }
+        };
+      }
+
+    static <A> P1<A> memo(F<Unit, A> f) {
+        return P.lazy(f).memo();
+    }
+
+    /**
+       * Returns a constant function that always uses this value.
+       *
+       * @return A constant function that always uses this value. 
+       */
+      public <B> F<B, A> constant() {
+
+        return new F<B, A>() {
+          public A f(final B b) {
+              return P1.this._1();
+          }
+        };
+      }
+
+    public String toString() {
+		return Show.p1Show(Show.<A>anyShow()).showS(this);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/P2.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,351 @@
+package fj;
+
+import static fj.Function.*;
+import fj.data.List;
+import fj.data.Stream;
+
+/**
+ * A product-2.
+ *
+ * @version %build.number%
+ */
+public abstract class P2<A, B> {
+  /**
+   * Access the first element of the product.
+   *
+   * @return The first element of the product.
+   */
+  public abstract A _1();
+
+  /**
+   * Access the second element of the product.
+   *
+   * @return The second element of the product.
+   */
+  public abstract B _2();
+
+  /**
+   * Swaps the elements around in this product.
+   *
+   * @return A new product-2 with the elements swapped.
+   */
+  public final P2<B, A> swap() {
+    return new P2<B, A>() {
+      public B _1() {
+        return P2.this._2();
+      }
+
+      public A _2() {
+        return P2.this._1();
+      }
+    };
+  }
+
+  /**
+   * Map the first element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P2<X, B> map1(final F<A, X> f) {
+    return new P2<X, B>() {
+      public X _1() {
+        return f.f(P2.this._1());
+      }
+
+      public B _2() {
+        return P2.this._2();
+      }
+    };
+  }
+
+  /**
+   * Map the second element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P2<A, X> map2(final F<B, X> f) {
+    return new P2<A, X>() {
+      public A _1() {
+        return P2.this._1();
+      }
+
+      public X _2() {
+        return f.f(P2.this._2());
+      }
+    };
+  }
+
+
+  /**
+   * Split this product between two argument functions and combine their output.
+   *
+   * @param f A function that will map the first element of this product.
+   * @param g A function that will map the second element of this product.
+   * @return A new product with the first function applied to the second element
+   *         and the second function applied to the second element.
+   */
+  public final <C, D> P2<C, D> split(final F<A, C> f, final F<B, D> g) {
+    final F<P2<A, D>, P2<C, D>> ff = map1_(f);
+    final F<P2<A, B>, P2<A, D>> gg = map2_(g);
+    return compose(ff, gg).f(this);
+  }
+
+  /**
+   * Duplicates this product on the first element, and maps the given function across the duplicate (Comonad pattern).
+   *
+   * @param k A function to map over the duplicated product.
+   * @return A new product with the result of the given function applied to this product as the first element,
+   *         and with the second element intact.
+   */
+  public final <C> P2<C, B> cobind(final F<P2<A, B>, C> k) {
+    return new P2<C, B>() {
+
+      public C _1() {
+        return k.f(P2.this);
+      }
+
+      public B _2() {
+        return P2.this._2();
+      }
+    };
+  }
+
+  /**
+   * Duplicates this product into the first element (Comonad pattern).
+   *
+   * @return A new product with this product in its first element and with the second element intact.
+   */
+  public final P2<P2<A, B>, B> duplicate() {
+    final F<P2<A, B>, P2<A, B>> id = identity();
+    return cobind(id);
+  }
+
+  /**
+   * Replaces the first element of this product with the given value.
+   *
+   * @param c The value with which to replace the first element of this product.
+   * @return A new product with the first element replaced with the given value.
+   */
+  public final <C> P2<C, B> inject(final C c) {
+    final F<P2<A, B>, C> co = constant(c);
+    return cobind(co);
+  }
+
+  /**
+   * Applies a list of comonadic functions to this product, returning a list of values.
+   *
+   * @param fs A list of functions to apply to this product.
+   * @return A list of the results of applying the given list of functions to this product.
+   */
+  public final <C> List<C> sequenceW(final List<F<P2<A, B>, C>> fs) {
+    List.Buffer<C> cs = List.Buffer.empty();
+    for (final F<P2<A, B>, C> f : fs)
+      cs = cs.snoc(f.f(this));
+    return cs.toList();
+  }
+
+  /**
+   * Applies a stream of comonadic functions to this product, returning a stream of values.
+   *
+   * @param fs A stream of functions to apply to this product.
+   * @return A stream of the results of applying the given stream of functions to this product.
+   */
+  public final <C> Stream<C> sequenceW(final Stream<F<P2<A, B>, C>> fs) {
+    return fs.isEmpty()
+           ? Stream.<C>nil()
+           : Stream.cons(fs.head().f(this), new P1<Stream<C>>() {
+             public Stream<C> _1() {
+               return sequenceW(fs.tail()._1());
+             }
+           });
+  }
+
+  /**
+   * Returns the 1-product projection over the first element.
+   *
+   * @return the 1-product projection over the first element.
+   */
+  public final P1<A> _1_() {
+    return F1Functions.lazy(P2.<A, B>__1()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the second element.
+   *
+   * @return the 1-product projection over the second element.
+   */
+  public final P1<B> _2_() {
+    return F1Functions.lazy(P2.<A, B>__2()).f(this);
+  }
+
+    /**
+     * Provides a memoising P2 that remembers its values.
+     *
+     * @return A P2 that calls this P2 once for any given element and remembers the value for subsequent calls.
+     */
+    public final P2<A, B> memo() {
+        P2<A, B> self = this;
+        return new P2<A, B>() {
+            private final P1<A> a = P1.memo(u -> self._1());
+            private final P1<B> b = P1.memo(u -> self._2());
+
+            public A _1() {
+                return a._1();
+            }
+
+            public B _2() {
+                return b._1();
+            }
+        };
+    }
+
+  /**
+   * A first-class version of the split function.
+   *
+   * @param f A function that will map the first element of the given product.
+   * @param g A function that will map the second element of the given product.
+   * @return A function that splits a given product between the two given functions and combines their output.
+   */
+  public static <A, B, C, D> F<P2<A, B>, P2<C, D>> split_(final F<A, C> f, final F<B, D> g) {
+    return new F<P2<A, B>, P2<C, D>>() {
+      public P2<C, D> f(final P2<A, B> p) {
+        return p.split(f, g);
+      }
+    };
+  }
+
+  /**
+   * Promotes a function so that it maps the first element of a product.
+   *
+   * @param f The function to promote.
+   * @return The given function, promoted to map the first element of products.
+   */
+  public static <A, B, X> F<P2<A, B>, P2<X, B>> map1_(final F<A, X> f) {
+    return new F<P2<A, B>, P2<X, B>>() {
+      public P2<X, B> f(final P2<A, B> p) {
+        return p.map1(f);
+      }
+    };
+  }
+
+  /**
+   * Promotes a function so that it maps the second element of a product.
+   *
+   * @param f The function to promote.
+   * @return The given function, promoted to map the second element of products.
+   */
+  public static <A, B, X> F<P2<A, B>, P2<A, X>> map2_(final F<B, X> f) {
+    return new F<P2<A, B>, P2<A, X>>() {
+      public P2<A, X> f(final P2<A, B> p) {
+        return p.map2(f);
+      }
+    };
+  }
+
+  /**
+   * Sends the given input value to both argument functions and combines their output.
+   *
+   * @param f A function to receive an input value.
+   * @param g A function to receive an input value.
+   * @param b An input value to send to both functions.
+   * @return The product of the two functions applied to the input value.
+   */
+  public static <B, C, D> P2<C, D> fanout(final F<B, C> f, final F<B, D> g, final B b) {
+    return join(P.<B, B>p2()).f(b).split(f, g);
+  }
+
+  /**
+   * Maps the given function across both the elements of the given product.
+   *
+   * @param f A function to map over a product.
+   * @param p A product over which to map.
+   * @return A new product with the given function applied to both elements.
+   */
+  public static <A, B> P2<B, B> map(final F<A, B> f, final P2<A, A> p) {
+    return p.split(f, f);
+  }
+
+  /**
+   * Returns a curried form of {@link #swap()}.
+   *
+   * @return A curried form of {@link #swap()}.
+   */
+  public static <A, B> F<P2<A, B>, P2<B, A>> swap_() {
+    return new F<P2<A, B>, P2<B, A>>() {
+      public P2<B, A> f(final P2<A, B> p) {
+        return p.swap();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the first element of a product.
+   *
+   * @return A function that returns the first element of a product.
+   */
+  public static <A, B> F<P2<A, B>, A> __1() {
+    return new F<P2<A, B>, A>() {
+      public A f(final P2<A, B> p) {
+        return p._1();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the second element of a product.
+   *
+   * @return A function that returns the second element of a product.
+   */
+  public static <A, B> F<P2<A, B>, B> __2() {
+    return new F<P2<A, B>, B>() {
+      public B f(final P2<A, B> p) {
+        return p._2();
+      }
+    };
+  }
+
+  /**
+   * Transforms a curried function of arity-2 to a function of a product-2
+   *
+   * @param f a curried function of arity-2 to transform into a function of a product-2
+   * @return The function, transformed to operate on on a product-2
+   */
+  public static <A, B, C> F<P2<A, B>, C> tuple(final F<A, F<B, C>> f) {
+    return new F<P2<A, B>, C>() {
+      public C f(final P2<A, B> p) {
+        return f.f(p._1()).f(p._2());
+      }
+    };
+  }
+
+  /**
+   * Transforms an uncurried function of arity-2 to a function of a product-2
+   *
+   * @param f an uncurried function of arity-2 to transform into a function of a product-2
+   * @return The function, transformed to operate on on a product-2
+   */
+  public static <A, B, C> F<P2<A, B>, C> tuple(final F2<A, B, C> f) {
+    return tuple(curry(f));
+  }
+
+  /**
+   * Transforms a function of a product-2 to an uncurried function or arity-2.
+   *
+   * @param f A function of a product-2 to transform into an uncurried function.
+   * @return The function, transformed to an uncurried function of arity-2.
+   */
+  public static <A, B, C> F2<A, B, C> untuple(final F<P2<A, B>, C> f) {
+    return new F2<A, B, C>() {
+      public C f(final A a, final B b) {
+        return f.f(P.p(a, b));
+      }
+    };
+  }
+
+	public String toString() {
+		return Show.p2Show(Show.<A>anyShow(), Show.<B>anyShow()).showS(this);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/P3.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,193 @@
+package fj;
+
+/**
+ * A product-3.
+ *
+ * @version %build.number%
+ */
+public abstract class P3<A, B, C> {
+  /**
+   * Access the first element of the product.
+   *
+   * @return The first element of the product.
+   */
+  public abstract A _1();
+
+  /**
+   * Access the second element of the product.
+   *
+   * @return The second element of the product.
+   */
+  public abstract B _2();
+
+  /**
+   * Access the third element of the product.
+   *
+   * @return The third element of the product.
+   */
+  public abstract C _3();
+
+  /**
+   * Map the first element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P3<X, B, C> map1(final F<A, X> f) {
+    return new P3<X, B, C>() {
+      public X _1() {
+        return f.f(P3.this._1());
+      }
+
+      public B _2() {
+        return P3.this._2();
+      }
+
+      public C _3() {
+        return P3.this._3();
+      }
+    };
+  }
+
+  /**
+   * Map the second element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P3<A, X, C> map2(final F<B, X> f) {
+    return new P3<A, X, C>() {
+      public A _1() {
+        return P3.this._1();
+      }
+
+      public X _2() {
+        return f.f(P3.this._2());
+      }
+
+      public C _3() {
+        return P3.this._3();
+      }
+    };
+  }
+
+  /**
+   * Map the third element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P3<A, B, X> map3(final F<C, X> f) {
+    return new P3<A, B, X>() {
+      public A _1() {
+        return P3.this._1();
+      }
+
+      public B _2() {
+        return P3.this._2();
+      }
+
+      public X _3() {
+        return f.f(P3.this._3());
+      }
+    };
+  }
+
+  /**
+   * Returns the 1-product projection over the first element.
+   *
+   * @return the 1-product projection over the first element.
+   */
+  public final P1<A> _1_() {
+    return F1Functions.lazy(P3.<A, B, C>__1()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the second element.
+   *
+   * @return the 1-product projection over the second element.
+   */
+  public final P1<B> _2_() {
+    return F1Functions.lazy(P3.<A, B, C>__2()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the third element.
+   *
+   * @return the 1-product projection over the third element.
+   */
+  public final P1<C> _3_() {
+    return F1Functions.lazy(P3.<A, B, C>__3()).f(this);
+  }
+
+  /**
+   * Provides a memoising P3 that remembers its values.
+   *
+   * @return A P3 that calls this P3 once for any given element and remembers the value for subsequent calls.
+   */
+  public final P3<A, B, C> memo() {
+      P3<A, B, C> self = this;
+    return new P3<A, B, C>() {
+      private final P1<A> a = P1.memo(u -> self._1());
+      private final P1<B> b = P1.memo(u -> self._2());
+      private final P1<C> c = P1.memo(u -> self._3());
+
+      public A _1() {
+        return a._1();
+      }
+
+      public B _2() {
+        return b._1();
+      }
+
+      public C _3() {
+        return c._1();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the first element of a product.
+   *
+   * @return A function that returns the first element of a product.
+   */
+  public static <A, B, C> F<P3<A, B, C>, A> __1() {
+    return new F<P3<A, B, C>, A>() {
+      public A f(final P3<A, B, C> p) {
+        return p._1();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the second element of a product.
+   *
+   * @return A function that returns the second element of a product.
+   */
+  public static <A, B, C> F<P3<A, B, C>, B> __2() {
+    return new F<P3<A, B, C>, B>() {
+      public B f(final P3<A, B, C> p) {
+        return p._2();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the third element of a product.
+   *
+   * @return A function that returns the third element of a product.
+   */
+  public static <A, B, C> F<P3<A, B, C>, C> __3() {
+    return new F<P3<A, B, C>, C>() {
+      public C f(final P3<A, B, C> p) {
+        return p._3();
+      }
+    };
+  }
+
+	public String toString() {
+		return Show.p3Show(Show.<A>anyShow(), Show.<B>anyShow(), Show.<C>anyShow()).showS(this);
+	}
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/P4.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,265 @@
+package fj;
+
+/**
+ * A product-4.
+ *
+ * @version %build.number%
+ */
+public abstract class P4<A, B, C, D> {
+  /**
+   * Access the first element of the product.
+   *
+   * @return The first element of the product.
+   */
+  public abstract A _1();
+
+  /**
+   * Access the second element of the product.
+   *
+   * @return The second element of the product.
+   */
+  public abstract B _2();
+
+  /**
+   * Access the third element of the product.
+   *
+   * @return The third element of the product.
+   */
+  public abstract C _3();
+
+  /**
+   * Access the fourth element of the product.
+   *
+   * @return The fourth element of the product.
+   */
+  public abstract D _4();
+
+  /**
+   * Map the first element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P4<X, B, C, D> map1(final F<A, X> f) {
+    return new P4<X, B, C, D>() {
+      public X _1() {
+        return f.f(P4.this._1());
+      }
+
+      public B _2() {
+        return P4.this._2();
+      }
+
+      public C _3() {
+        return P4.this._3();
+      }
+
+      public D _4() {
+        return P4.this._4();
+      }
+    };
+  }
+
+  /**
+   * Map the second element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P4<A, X, C, D> map2(final F<B, X> f) {
+    return new P4<A, X, C, D>() {
+      public A _1() {
+        return P4.this._1();
+      }
+
+      public X _2() {
+        return f.f(P4.this._2());
+      }
+
+      public C _3() {
+        return P4.this._3();
+      }
+
+      public D _4() {
+        return P4.this._4();
+      }
+    };
+  }
+
+  /**
+   * Map the third element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P4<A, B, X, D> map3(final F<C, X> f) {
+    return new P4<A, B, X, D>() {
+      public A _1() {
+        return P4.this._1();
+      }
+
+      public B _2() {
+        return P4.this._2();
+      }
+
+      public X _3() {
+        return f.f(P4.this._3());
+      }
+
+      public D _4() {
+        return P4.this._4();
+      }
+    };
+  }
+
+  /**
+   * Map the fourth element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P4<A, B, C, X> map4(final F<D, X> f) {
+    return new P4<A, B, C, X>() {
+      public A _1() {
+        return P4.this._1();
+      }
+
+      public B _2() {
+        return P4.this._2();
+      }
+
+      public C _3() {
+        return P4.this._3();
+      }
+
+      public X _4() {
+        return f.f(P4.this._4());
+      }
+    };
+  }
+
+  /**
+   * Returns the 1-product projection over the first element.
+   *
+   * @return the 1-product projection over the first element.
+   */
+  public final P1<A> _1_() {
+    return F1Functions.lazy(P4.<A, B, C, D>__1()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the second element.
+   *
+   * @return the 1-product projection over the second element.
+   */
+  public final P1<B> _2_() {
+    return F1Functions.lazy(P4.<A, B, C, D>__2()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the third element.
+   *
+   * @return the 1-product projection over the third element.
+   */
+  public final P1<C> _3_() {
+    return F1Functions.lazy(P4.<A, B, C, D>__3()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the fourth element.
+   *
+   * @return the 1-product projection over the fourth element.
+   */
+  public final P1<D> _4_() {
+    return F1Functions.lazy(P4.<A, B, C, D>__4()).f(this);
+  }
+
+  /**
+   * Provides a memoising P4 that remembers its values.
+   *
+   * @return A P4 that calls this P4 once for any given element and remembers the value for subsequent calls.
+   */
+  public final P4<A, B, C, D> memo() {
+      P4<A, B, C, D> self = this;
+    return new P4<A, B, C, D>() {
+      private final P1<A> a = P1.memo(u -> self._1());
+      private final P1<B> b = P1.memo(u -> self._2());
+      private final P1<C> c = P1.memo(u -> self._3());
+      private final P1<D> d = P1.memo(u -> self._4());
+
+      public A _1() {
+        return a._1();
+      }
+
+      public B _2() {
+        return b._1();
+      }
+
+      public C _3() {
+        return c._1();
+      }
+
+      public D _4() {
+        return d._1();
+      }
+    };
+  }
+
+
+  /**
+   * Returns a function that returns the first element of a product.
+   *
+   * @return A function that returns the first element of a product.
+   */
+  public static <A, B, C, D> F<P4<A, B, C, D>, A> __1() {
+    return new F<P4<A, B, C, D>, A>() {
+      public A f(final P4<A, B, C, D> p) {
+        return p._1();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the second element of a product.
+   *
+   * @return A function that returns the second element of a product.
+   */
+  public static <A, B, C, D> F<P4<A, B, C, D>, B> __2() {
+    return new F<P4<A, B, C, D>, B>() {
+      public B f(final P4<A, B, C, D> p) {
+        return p._2();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the third element of a product.
+   *
+   * @return A function that returns the third element of a product.
+   */
+  public static <A, B, C, D> F<P4<A, B, C, D>, C> __3() {
+    return new F<P4<A, B, C, D>, C>() {
+      public C f(final P4<A, B, C, D> p) {
+        return p._3();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the fourth element of a product.
+   *
+   * @return A function that returns the fourth element of a product.
+   */
+  public static <A, B, C, D> F<P4<A, B, C, D>, D> __4() {
+    return new F<P4<A, B, C, D>, D>() {
+      public D f(final P4<A, B, C, D> p) {
+        return p._4();
+      }
+    };
+  }
+
+	public String toString() {
+		return Show.p4Show(Show.<A>anyShow(), Show.<B>anyShow(), Show.<C>anyShow(), Show.<D>anyShow()).showS(this);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/P5.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,345 @@
+package fj;
+
+/**
+ * A product-5.
+ *
+ * @version %build.number%
+ */
+public abstract class P5<A, B, C, D, E> {
+  /**
+   * Access the first element of the product.
+   *
+   * @return The first element of the product.
+   */
+  public abstract A _1();
+
+  /**
+   * Access the second element of the product.
+   *
+   * @return The second element of the product.
+   */
+  public abstract B _2();
+
+  /**
+   * Access the third element of the product.
+   *
+   * @return The third element of the product.
+   */
+  public abstract C _3();
+
+  /**
+   * Access the fourth element of the product.
+   *
+   * @return The fourth element of the product.
+   */
+  public abstract D _4();
+
+  /**
+   * Access the fifth element of the product.
+   *
+   * @return The fifth element of the product.
+   */
+  public abstract E _5();
+
+  /**
+   * Map the first element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P5<X, B, C, D, E> map1(final F<A, X> f) {
+    return new P5<X, B, C, D, E>() {
+      public X _1() {
+        return f.f(P5.this._1());
+      }
+
+      public B _2() {
+        return P5.this._2();
+      }
+
+      public C _3() {
+        return P5.this._3();
+      }
+
+      public D _4() {
+        return P5.this._4();
+      }
+
+      public E _5() {
+        return P5.this._5();
+      }
+    };
+  }
+
+  /**
+   * Map the second element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P5<A, X, C, D, E> map2(final F<B, X> f) {
+    return new P5<A, X, C, D, E>() {
+      public A _1() {
+        return P5.this._1();
+      }
+
+      public X _2() {
+        return f.f(P5.this._2());
+      }
+
+      public C _3() {
+        return P5.this._3();
+      }
+
+      public D _4() {
+        return P5.this._4();
+      }
+
+      public E _5() {
+        return P5.this._5();
+      }
+    };
+  }
+
+  /**
+   * Map the third element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P5<A, B, X, D, E> map3(final F<C, X> f) {
+    return new P5<A, B, X, D, E>() {
+      public A _1() {
+        return P5.this._1();
+      }
+
+      public B _2() {
+        return P5.this._2();
+      }
+
+      public X _3() {
+        return f.f(P5.this._3());
+      }
+
+      public D _4() {
+        return P5.this._4();
+      }
+
+      public E _5() {
+        return P5.this._5();
+      }
+    };
+  }
+
+  /**
+   * Map the fourth element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P5<A, B, C, X, E> map4(final F<D, X> f) {
+    return new P5<A, B, C, X, E>() {
+      public A _1() {
+        return P5.this._1();
+      }
+
+      public B _2() {
+        return P5.this._2();
+      }
+
+      public C _3() {
+        return P5.this._3();
+      }
+
+      public X _4() {
+        return f.f(P5.this._4());
+      }
+
+      public E _5() {
+        return P5.this._5();
+      }
+    };
+  }
+
+  /**
+   * Map the fifth element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P5<A, B, C, D, X> map5(final F<E, X> f) {
+    return new P5<A, B, C, D, X>() {
+      public A _1() {
+        return P5.this._1();
+      }
+
+      public B _2() {
+        return P5.this._2();
+      }
+
+      public C _3() {
+        return P5.this._3();
+      }
+
+      public D _4() {
+        return P5.this._4();
+      }
+
+      public X _5() {
+        return f.f(P5.this._5());
+      }
+    };
+  }
+
+  /**
+   * Returns the 1-product projection over the first element.
+   *
+   * @return the 1-product projection over the first element.
+   */
+  public final P1<A> _1_() {
+    return F1Functions.lazy(P5.<A, B, C, D, E>__1()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the second element.
+   *
+   * @return the 1-product projection over the second element.
+   */
+  public final P1<B> _2_() {
+    return F1Functions.lazy(P5.<A, B, C, D, E>__2()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the third element.
+   *
+   * @return the 1-product projection over the third element.
+   */
+  public final P1<C> _3_() {
+    return F1Functions.lazy(P5.<A, B, C, D, E>__3()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the fourth element.
+   *
+   * @return the 1-product projection over the fourth element.
+   */
+  public final P1<D> _4_() {
+    return F1Functions.lazy(P5.<A, B, C, D, E>__4()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the fifth element.
+   *
+   * @return the 1-product projection over the fifth element.
+   */
+  public final P1<E> _5_() {
+    return F1Functions.lazy(P5.<A, B, C, D, E>__5()).f(this);
+  }
+
+  /**
+   * Provides a memoising P5 that remembers its values.
+   *
+   * @return A P5 that calls this P5 once for any given element and remembers the value for subsequent calls.
+   */
+  public final P5<A, B, C, D, E> memo() {
+      P5<A, B, C, D, E> self = this;
+    return new P5<A, B, C, D, E>() {
+      private final P1<A> a = P1.memo(u -> self._1());
+      private final P1<B> b = P1.memo(u -> self._2());
+      private final P1<C> c = P1.memo(u -> self._3());
+      private final P1<D> d = P1.memo(u -> self._4());
+      private final P1<E> e = P1.memo(u -> self._5());
+
+      public A _1() {
+        return a._1();
+      }
+
+      public B _2() {
+        return b._1();
+      }
+
+      public C _3() {
+        return c._1();
+      }
+
+      public D _4() {
+        return d._1();
+      }
+
+      public E _5() {
+        return e._1();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the first element of a product.
+   *
+   * @return A function that returns the first element of a product.
+   */
+  public static <A, B, C, D, E> F<P5<A, B, C, D, E>, A> __1() {
+    return new F<P5<A, B, C, D, E>, A>() {
+      public A f(final P5<A, B, C, D, E> p) {
+        return p._1();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the second element of a product.
+   *
+   * @return A function that returns the second element of a product.
+   */
+  public static <A, B, C, D, E> F<P5<A, B, C, D, E>, B> __2() {
+    return new F<P5<A, B, C, D, E>, B>() {
+      public B f(final P5<A, B, C, D, E> p) {
+        return p._2();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the third element of a product.
+   *
+   * @return A function that returns the third element of a product.
+   */
+  public static <A, B, C, D, E> F<P5<A, B, C, D, E>, C> __3() {
+    return new F<P5<A, B, C, D, E>, C>() {
+      public C f(final P5<A, B, C, D, E> p) {
+        return p._3();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the fourth element of a product.
+   *
+   * @return A function that returns the fourth element of a product.
+   */
+  public static <A, B, C, D, E> F<P5<A, B, C, D, E>, D> __4() {
+    return new F<P5<A, B, C, D, E>, D>() {
+      public D f(final P5<A, B, C, D, E> p) {
+        return p._4();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the fifth element of a product.
+   *
+   * @return A function that returns the fifth element of a product.
+   */
+  public static <A, B, C, D, E> F<P5<A, B, C, D, E>, E> __5() {
+    return new F<P5<A, B, C, D, E>, E>() {
+      public E f(final P5<A, B, C, D, E> p) {
+        return p._5();
+      }
+    };
+  }
+
+	public String toString() {
+		return Show.p5Show(Show.<A>anyShow(), Show.<B>anyShow(), Show.<C>anyShow(), Show.<D>anyShow(), Show.<E>anyShow()).showS(this);
+	}
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/P6.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,434 @@
+package fj;
+
+/**
+ * A product-6.
+ *
+ * @version %build.number%
+ */
+@SuppressWarnings({"UnnecessaryFullyQualifiedName"})
+public abstract class P6<A, B, C, D, E, F> {
+  /**
+   * Access the first element of the product.
+   *
+   * @return The first element of the product.
+   */
+  public abstract A _1();
+
+  /**
+   * Access the second element of the product.
+   *
+   * @return The second element of the product.
+   */
+  public abstract B _2();
+
+  /**
+   * Access the third element of the product.
+   *
+   * @return The third element of the product.
+   */
+  public abstract C _3();
+
+  /**
+   * Access the fourth element of the product.
+   *
+   * @return The fourth element of the product.
+   */
+  public abstract D _4();
+
+  /**
+   * Access the fifth element of the product.
+   *
+   * @return The fifth element of the product.
+   */
+  public abstract E _5();
+
+  /**
+   * Access the sixth element of the product.
+   *
+   * @return The sixth element of the product.
+   */
+  public abstract F _6();
+
+  /**
+   * Map the first element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P6<X, B, C, D, E, F> map1(final fj.F<A, X> f) {
+    return new P6<X, B, C, D, E, F>() {
+      public X _1() {
+        return f.f(P6.this._1());
+      }
+
+      public B _2() {
+        return P6.this._2();
+      }
+
+      public C _3() {
+        return P6.this._3();
+      }
+
+      public D _4() {
+        return P6.this._4();
+      }
+
+      public E _5() {
+        return P6.this._5();
+      }
+
+      public F _6() {
+        return P6.this._6();
+      }
+    };
+  }
+
+  /**
+   * Map the second element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P6<A, X, C, D, E, F> map2(final fj.F<B, X> f) {
+    return new P6<A, X, C, D, E, F>() {
+      public A _1() {
+        return P6.this._1();
+      }
+
+      public X _2() {
+        return f.f(P6.this._2());
+      }
+
+      public C _3() {
+        return P6.this._3();
+      }
+
+      public D _4() {
+        return P6.this._4();
+      }
+
+      public E _5() {
+        return P6.this._5();
+      }
+
+      public F _6() {
+        return P6.this._6();
+      }
+    };
+  }
+
+  /**
+   * Map the third element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P6<A, B, X, D, E, F> map3(final fj.F<C, X> f) {
+    return new P6<A, B, X, D, E, F>() {
+      public A _1() {
+        return P6.this._1();
+      }
+
+      public B _2() {
+        return P6.this._2();
+      }
+
+      public X _3() {
+        return f.f(P6.this._3());
+      }
+
+      public D _4() {
+        return P6.this._4();
+      }
+
+      public E _5() {
+        return P6.this._5();
+      }
+
+      public F _6() {
+        return P6.this._6();
+      }
+    };
+  }
+
+  /**
+   * Map the fourth element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P6<A, B, C, X, E, F> map4(final fj.F<D, X> f) {
+    return new P6<A, B, C, X, E, F>() {
+      public A _1() {
+        return P6.this._1();
+      }
+
+      public B _2() {
+        return P6.this._2();
+      }
+
+      public C _3() {
+        return P6.this._3();
+      }
+
+      public X _4() {
+        return f.f(P6.this._4());
+      }
+
+      public E _5() {
+        return P6.this._5();
+      }
+
+      public F _6() {
+        return P6.this._6();
+      }
+    };
+  }
+
+  /**
+   * Map the fifth element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P6<A, B, C, D, X, F> map5(final fj.F<E, X> f) {
+    return new P6<A, B, C, D, X, F>() {
+      public A _1() {
+        return P6.this._1();
+      }
+
+      public B _2() {
+        return P6.this._2();
+      }
+
+      public C _3() {
+        return P6.this._3();
+      }
+
+      public D _4() {
+        return P6.this._4();
+      }
+
+      public X _5() {
+        return f.f(P6.this._5());
+      }
+
+      public F _6() {
+        return P6.this._6();
+      }
+    };
+  }
+
+  /**
+   * Map the sixth element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P6<A, B, C, D, E, X> map6(final fj.F<F, X> f) {
+    return new P6<A, B, C, D, E, X>() {
+      public A _1() {
+        return P6.this._1();
+      }
+
+      public B _2() {
+        return P6.this._2();
+      }
+
+      public C _3() {
+        return P6.this._3();
+      }
+
+      public D _4() {
+        return P6.this._4();
+      }
+
+      public E _5() {
+        return P6.this._5();
+      }
+
+      public X _6() {
+        return f.f(P6.this._6());
+      }
+    };
+  }
+
+  /**
+   * Returns the 1-product projection over the first element.
+   *
+   * @return the 1-product projection over the first element.
+   */
+  public final P1<A> _1_() {
+    return F1Functions.lazy(P6.<A, B, C, D, E, F>__1()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the second element.
+   *
+   * @return the 1-product projection over the second element.
+   */
+  public final P1<B> _2_() {
+    return F1Functions.lazy(P6.<A, B, C, D, E, F>__2()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the third element.
+   *
+   * @return the 1-product projection over the third element.
+   */
+  public final P1<C> _3_() {
+    return F1Functions.lazy(P6.<A, B, C, D, E, F>__3()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the fourth element.
+   *
+   * @return the 1-product projection over the fourth element.
+   */
+  public final P1<D> _4_() {
+    return F1Functions.lazy(P6.<A, B, C, D, E, F>__4()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the fifth element.
+   *
+   * @return the 1-product projection over the fifth element.
+   */
+  public final P1<E> _5_() {
+    return F1Functions.lazy(P6.<A, B, C, D, E, F>__5()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the sixth element.
+   *
+   * @return the 1-product projection over the sixth element.
+   */
+  public final P1<F> _6_() {
+    return F1Functions.lazy(P6.<A, B, C, D, E, F>__6()).f(this);
+  }
+
+  /**
+   * Provides a memoising P6 that remembers its values.
+   *
+   * @return A P6 that calls this P6 once for any given element and remembers the value for subsequent calls.
+   */
+  public final P6<A, B, C, D, E, F> memo() {
+      P6<A, B, C, D, E, F> self = this;
+    return new P6<A, B, C, D, E, F>() {
+      private final P1<A> a = P1.memo(u -> self._1());
+      private final P1<B> b = P1.memo(u -> self._2());
+      private final P1<C> c = P1.memo(u -> self._3());
+      private final P1<D> d = P1.memo(u -> self._4());
+      private final P1<E> e = P1.memo(u -> self._5());
+      private final P1<F> f = P1.memo(u -> self._6());
+
+      public A _1() {
+        return a._1();
+      }
+
+      public B _2() {
+        return b._1();
+      }
+
+      public C _3() {
+        return c._1();
+      }
+
+      public D _4() {
+        return d._1();
+      }
+
+      public E _5() {
+        return e._1();
+      }
+
+      public F _6() {
+        return f._1();
+      }
+    };
+  }
+
+
+  /**
+   * Returns a function that returns the first element of a product.
+   *
+   * @return A function that returns the first element of a product.
+   */
+  public static <A, B, C, D, E, F$> fj.F<P6<A, B, C, D, E, F$>, A> __1() {
+    return new fj.F<P6<A, B, C, D, E, F$>, A>() {
+      public A f(final P6<A, B, C, D, E, F$> p) {
+        return p._1();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the second element of a product.
+   *
+   * @return A function that returns the second element of a product.
+   */
+  public static <A, B, C, D, E, F$> fj.F<P6<A, B, C, D, E, F$>, B> __2() {
+    return new fj.F<P6<A, B, C, D, E, F$>, B>() {
+      public B f(final P6<A, B, C, D, E, F$> p) {
+        return p._2();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the third element of a product.
+   *
+   * @return A function that returns the third element of a product.
+   */
+  public static <A, B, C, D, E, F$> fj.F<P6<A, B, C, D, E, F$>, C> __3() {
+    return new fj.F<P6<A, B, C, D, E, F$>, C>() {
+      public C f(final P6<A, B, C, D, E, F$> p) {
+        return p._3();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the fourth element of a product.
+   *
+   * @return A function that returns the fourth element of a product.
+   */
+  public static <A, B, C, D, E, F$> fj.F<P6<A, B, C, D, E, F$>, D> __4() {
+    return new fj.F<P6<A, B, C, D, E, F$>, D>() {
+      public D f(final P6<A, B, C, D, E, F$> p) {
+        return p._4();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the fifth element of a product.
+   *
+   * @return A function that returns the fifth element of a product.
+   */
+  public static <A, B, C, D, E, F$> fj.F<P6<A, B, C, D, E, F$>, E> __5() {
+    return new fj.F<P6<A, B, C, D, E, F$>, E>() {
+      public E f(final P6<A, B, C, D, E, F$> p) {
+        return p._5();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the sixth element of a product.
+   *
+   * @return A function that returns the sixth element of a product.
+   */
+  public static <A, B, C, D, E, F$> fj.F<P6<A, B, C, D, E, F$>, F$> __6() {
+    return new fj.F<P6<A, B, C, D, E, F$>, F$>() {
+      public F$ f(final P6<A, B, C, D, E, F$> p) {
+        return p._6();
+      }
+    };
+  }
+
+	public String toString() {
+		return Show.p6Show(Show.<A>anyShow(), Show.<B>anyShow(), Show.<C>anyShow(), Show.<D>anyShow(), Show.<E>anyShow(), Show.<F>anyShow()).showS(this);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/P7.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,530 @@
+package fj;
+
+/**
+ * A product-7.
+ *
+ * @version %build.number%
+ */
+@SuppressWarnings({"UnnecessaryFullyQualifiedName"})
+public abstract class P7<A, B, C, D, E, F, G> {
+  /**
+   * Access the first element of the product.
+   *
+   * @return The first element of the product.
+   */
+  public abstract A _1();
+
+  /**
+   * Access the second element of the product.
+   *
+   * @return The second element of the product.
+   */
+  public abstract B _2();
+
+  /**
+   * Access the third element of the product.
+   *
+   * @return The third element of the product.
+   */
+  public abstract C _3();
+
+  /**
+   * Access the fourth element of the product.
+   *
+   * @return The fourth element of the product.
+   */
+  public abstract D _4();
+
+  /**
+   * Access the fifth element of the product.
+   *
+   * @return The fifth element of the product.
+   */
+  public abstract E _5();
+
+  /**
+   * Access the sixth element of the product.
+   *
+   * @return The sixth element of the product.
+   */
+  public abstract F _6();
+
+  /**
+   * Access the seventh element of the product.
+   *
+   * @return The seventh element of the product.
+   */
+  public abstract G _7();
+
+  /**
+   * Map the first element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P7<X, B, C, D, E, F, G> map1(final fj.F<A, X> f) {
+    return new P7<X, B, C, D, E, F, G>() {
+      public X _1() {
+        return f.f(P7.this._1());
+      }
+
+      public B _2() {
+        return P7.this._2();
+      }
+
+      public C _3() {
+        return P7.this._3();
+      }
+
+      public D _4() {
+        return P7.this._4();
+      }
+
+      public E _5() {
+        return P7.this._5();
+      }
+
+      public F _6() {
+        return P7.this._6();
+      }
+
+      public G _7() {
+        return P7.this._7();
+      }
+    };
+  }
+
+  /**
+   * Map the second element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P7<A, X, C, D, E, F, G> map2(final fj.F<B, X> f) {
+    return new P7<A, X, C, D, E, F, G>() {
+      public A _1() {
+        return P7.this._1();
+      }
+
+      public X _2() {
+        return f.f(P7.this._2());
+      }
+
+      public C _3() {
+        return P7.this._3();
+      }
+
+      public D _4() {
+        return P7.this._4();
+      }
+
+      public E _5() {
+        return P7.this._5();
+      }
+
+      public F _6() {
+        return P7.this._6();
+      }
+
+      public G _7() {
+        return P7.this._7();
+      }
+    };
+  }
+
+  /**
+   * Map the third element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P7<A, B, X, D, E, F, G> map3(final fj.F<C, X> f) {
+    return new P7<A, B, X, D, E, F, G>() {
+      public A _1() {
+        return P7.this._1();
+      }
+
+      public B _2() {
+        return P7.this._2();
+      }
+
+      public X _3() {
+        return f.f(P7.this._3());
+      }
+
+      public D _4() {
+        return P7.this._4();
+      }
+
+      public E _5() {
+        return P7.this._5();
+      }
+
+      public F _6() {
+        return P7.this._6();
+      }
+
+      public G _7() {
+        return P7.this._7();
+      }
+    };
+  }
+
+  /**
+   * Map the fourth element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P7<A, B, C, X, E, F, G> map4(final fj.F<D, X> f) {
+    return new P7<A, B, C, X, E, F, G>() {
+      public A _1() {
+        return P7.this._1();
+      }
+
+      public B _2() {
+        return P7.this._2();
+      }
+
+      public C _3() {
+        return P7.this._3();
+      }
+
+      public X _4() {
+        return f.f(P7.this._4());
+      }
+
+      public E _5() {
+        return P7.this._5();
+      }
+
+      public F _6() {
+        return P7.this._6();
+      }
+
+      public G _7() {
+        return P7.this._7();
+      }
+    };
+  }
+
+  /**
+   * Map the fifth element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P7<A, B, C, D, X, F, G> map5(final fj.F<E, X> f) {
+    return new P7<A, B, C, D, X, F, G>() {
+      public A _1() {
+        return P7.this._1();
+      }
+
+      public B _2() {
+        return P7.this._2();
+      }
+
+      public C _3() {
+        return P7.this._3();
+      }
+
+      public D _4() {
+        return P7.this._4();
+      }
+
+      public X _5() {
+        return f.f(P7.this._5());
+      }
+
+      public F _6() {
+        return P7.this._6();
+      }
+
+      public G _7() {
+        return P7.this._7();
+      }
+    };
+  }
+
+  /**
+   * Map the sixth element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P7<A, B, C, D, E, X, G> map6(final fj.F<F, X> f) {
+    return new P7<A, B, C, D, E, X, G>() {
+      public A _1() {
+        return P7.this._1();
+      }
+
+      public B _2() {
+        return P7.this._2();
+      }
+
+      public C _3() {
+        return P7.this._3();
+      }
+
+      public D _4() {
+        return P7.this._4();
+      }
+
+      public E _5() {
+        return P7.this._5();
+      }
+
+      public X _6() {
+        return f.f(P7.this._6());
+      }
+
+      public G _7() {
+        return P7.this._7();
+      }
+    };
+  }
+
+  /**
+   * Map the seventh element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P7<A, B, C, D, E, F, X> map7(final fj.F<G, X> f) {
+    return new P7<A, B, C, D, E, F, X>() {
+      public A _1() {
+        return P7.this._1();
+      }
+
+      public B _2() {
+        return P7.this._2();
+      }
+
+      public C _3() {
+        return P7.this._3();
+      }
+
+      public D _4() {
+        return P7.this._4();
+      }
+
+      public E _5() {
+        return P7.this._5();
+      }
+
+      public F _6() {
+        return P7.this._6();
+      }
+
+      public X _7() {
+        return f.f(P7.this._7());
+      }
+    };
+  }
+
+  /**
+   * Returns the 1-product projection over the first element.
+   *
+   * @return the 1-product projection over the first element.
+   */
+  public final P1<A> _1_() {
+    return F1Functions.lazy(P7.<A, B, C, D, E, F, G>__1()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the second element.
+   *
+   * @return the 1-product projection over the second element.
+   */
+  public final P1<B> _2_() {
+    return F1Functions.lazy(P7.<A, B, C, D, E, F, G>__2()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the third element.
+   *
+   * @return the 1-product projection over the third element.
+   */
+  public final P1<C> _3_() {
+    return F1Functions.lazy(P7.<A, B, C, D, E, F, G>__3()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the fourth element.
+   *
+   * @return the 1-product projection over the fourth element.
+   */
+  public final P1<D> _4_() {
+    return F1Functions.lazy(P7.<A, B, C, D, E, F, G>__4()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the fifth element.
+   *
+   * @return the 1-product projection over the fifth element.
+   */
+  public final P1<E> _5_() {
+    return F1Functions.lazy(P7.<A, B, C, D, E, F, G>__5()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the sixth element.
+   *
+   * @return the 1-product projection over the sixth element.
+   */
+  public final P1<F> _6_() {
+    return F1Functions.lazy(P7.<A, B, C, D, E, F, G>__6()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the seventh element.
+   *
+   * @return the 1-product projection over the seventh element.
+   */
+  public final P1<G> _7_() {
+    return F1Functions.lazy(P7.<A, B, C, D, E, F, G>__7()).f(this);
+  }
+
+  /**
+   * Provides a memoising P7 that remembers its values.
+   *
+   * @return A P7 that calls this P7 once for any given element and remembers the value for subsequent calls.
+   */
+  public final P7<A, B, C, D, E, F, G> memo() {
+      P7<A, B, C, D, E, F, G> self = this;
+    return new P7<A, B, C, D, E, F, G>() {
+      private final P1<A> a = P1.memo(u -> self._1());
+      private final P1<B> b = P1.memo(u -> self._2());
+      private final P1<C> c = P1.memo(u -> self._3());
+      private final P1<D> d = P1.memo(u -> self._4());
+      private final P1<E> e = P1.memo(u -> self._5());
+      private final P1<F> f = P1.memo(u -> self._6());
+      private final P1<G> g = P1.memo(u -> self._7());
+
+      public A _1() {
+        return a._1();
+      }
+
+      public B _2() {
+        return b._1();
+      }
+
+      public C _3() {
+        return c._1();
+      }
+
+      public D _4() {
+        return d._1();
+      }
+
+      public E _5() {
+        return e._1();
+      }
+
+      public F _6() {
+        return f._1();
+      }
+
+      public G _7() {
+        return g._1();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the first element of a product.
+   *
+   * @return A function that returns the first element of a product.
+   */
+  public static <A, B, C, D, E, F$, G> fj.F<P7<A, B, C, D, E, F$, G>, A> __1() {
+    return new fj.F<P7<A, B, C, D, E, F$, G>, A>() {
+      public A f(final P7<A, B, C, D, E, F$, G> p) {
+        return p._1();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the second element of a product.
+   *
+   * @return A function that returns the second element of a product.
+   */
+  public static <A, B, C, D, E, F$, G> fj.F<P7<A, B, C, D, E, F$, G>, B> __2() {
+    return new fj.F<P7<A, B, C, D, E, F$, G>, B>() {
+      public B f(final P7<A, B, C, D, E, F$, G> p) {
+        return p._2();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the third element of a product.
+   *
+   * @return A function that returns the third element of a product.
+   */
+  public static <A, B, C, D, E, F$, G> fj.F<P7<A, B, C, D, E, F$, G>, C> __3() {
+    return new fj.F<P7<A, B, C, D, E, F$, G>, C>() {
+      public C f(final P7<A, B, C, D, E, F$, G> p) {
+        return p._3();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the fourth element of a product.
+   *
+   * @return A function that returns the fourth element of a product.
+   */
+  public static <A, B, C, D, E, F$, G> fj.F<P7<A, B, C, D, E, F$, G>, D> __4() {
+    return new fj.F<P7<A, B, C, D, E, F$, G>, D>() {
+      public D f(final P7<A, B, C, D, E, F$, G> p) {
+        return p._4();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the fifth element of a product.
+   *
+   * @return A function that returns the fifth element of a product.
+   */
+  public static <A, B, C, D, E, F$, G> fj.F<P7<A, B, C, D, E, F$, G>, E> __5() {
+    return new fj.F<P7<A, B, C, D, E, F$, G>, E>() {
+      public E f(final P7<A, B, C, D, E, F$, G> p) {
+        return p._5();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the sixth element of a product.
+   *
+   * @return A function that returns the sixth element of a product.
+   */
+  public static <A, B, C, D, E, F$, G> fj.F<P7<A, B, C, D, E, F$, G>, F$> __6() {
+    return new fj.F<P7<A, B, C, D, E, F$, G>, F$>() {
+      public F$ f(final P7<A, B, C, D, E, F$, G> p) {
+        return p._6();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the seventh element of a product.
+   *
+   * @return A function that returns the seventh element of a product.
+   */
+  public static <A, B, C, D, E, F$, G> fj.F<P7<A, B, C, D, E, F$, G>, G> __7() {
+    return new fj.F<P7<A, B, C, D, E, F$, G>, G>() {
+      public G f(final P7<A, B, C, D, E, F$, G> p) {
+        return p._7();
+      }
+    };
+  }
+
+	public String toString() {
+		return Show.p7Show(Show.<A>anyShow(), Show.<B>anyShow(), Show.<C>anyShow(), Show.<D>anyShow(), Show.<E>anyShow(), Show.<F>anyShow(), Show.<G>anyShow()).showS(this);
+	}
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/P8.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,635 @@
+package fj;
+
+/**
+ * A product-8.
+ *
+ * @version %build.number%
+ */
+@SuppressWarnings({"UnnecessaryFullyQualifiedName"})
+public abstract class P8<A, B, C, D, E, F, G, H> {
+  /**
+   * Access the first element of the product.
+   *
+   * @return The first element of the product.
+   */
+  public abstract A _1();
+
+  /**
+   * Access the second element of the product.
+   *
+   * @return The second element of the product.
+   */
+  public abstract B _2();
+
+  /**
+   * Access the third element of the product.
+   *
+   * @return The third element of the product.
+   */
+  public abstract C _3();
+
+  /**
+   * Access the fourth element of the product.
+   *
+   * @return The fourth element of the product.
+   */
+  public abstract D _4();
+
+  /**
+   * Access the fifth element of the product.
+   *
+   * @return The fifth element of the product.
+   */
+  public abstract E _5();
+
+  /**
+   * Access the sixth element of the product.
+   *
+   * @return The sixth element of the product.
+   */
+  public abstract F _6();
+
+  /**
+   * Access the seventh element of the product.
+   *
+   * @return The seventh element of the product.
+   */
+  public abstract G _7();
+
+  /**
+   * Access the eighth element of the product.
+   *
+   * @return The eighth element of the product.
+   */
+  public abstract H _8();
+
+  /**
+   * Map the first element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P8<X, B, C, D, E, F, G, H> map1(final fj.F<A, X> f) {
+    return new P8<X, B, C, D, E, F, G, H>() {
+      public X _1() {
+        return f.f(P8.this._1());
+      }
+
+      public B _2() {
+        return P8.this._2();
+      }
+
+      public C _3() {
+        return P8.this._3();
+      }
+
+      public D _4() {
+        return P8.this._4();
+      }
+
+      public E _5() {
+        return P8.this._5();
+      }
+
+      public F _6() {
+        return P8.this._6();
+      }
+
+      public G _7() {
+        return P8.this._7();
+      }
+
+      public H _8() {
+        return P8.this._8();
+      }
+    };
+  }
+
+  /**
+   * Map the second element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P8<A, X, C, D, E, F, G, H> map2(final fj.F<B, X> f) {
+    return new P8<A, X, C, D, E, F, G, H>() {
+      public A _1() {
+        return P8.this._1();
+      }
+
+      public X _2() {
+        return f.f(P8.this._2());
+      }
+
+      public C _3() {
+        return P8.this._3();
+      }
+
+      public D _4() {
+        return P8.this._4();
+      }
+
+      public E _5() {
+        return P8.this._5();
+      }
+
+      public F _6() {
+        return P8.this._6();
+      }
+
+      public G _7() {
+        return P8.this._7();
+      }
+
+      public H _8() {
+        return P8.this._8();
+      }
+    };
+  }
+
+  /**
+   * Map the third element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P8<A, B, X, D, E, F, G, H> map3(final fj.F<C, X> f) {
+    return new P8<A, B, X, D, E, F, G, H>() {
+      public A _1() {
+        return P8.this._1();
+      }
+
+      public B _2() {
+        return P8.this._2();
+      }
+
+      public X _3() {
+        return f.f(P8.this._3());
+      }
+
+      public D _4() {
+        return P8.this._4();
+      }
+
+      public E _5() {
+        return P8.this._5();
+      }
+
+      public F _6() {
+        return P8.this._6();
+      }
+
+      public G _7() {
+        return P8.this._7();
+      }
+
+      public H _8() {
+        return P8.this._8();
+      }
+    };
+  }
+
+  /**
+   * Map the fourth element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P8<A, B, C, X, E, F, G, H> map4(final fj.F<D, X> f) {
+    return new P8<A, B, C, X, E, F, G, H>() {
+      public A _1() {
+        return P8.this._1();
+      }
+
+      public B _2() {
+        return P8.this._2();
+      }
+
+      public C _3() {
+        return P8.this._3();
+      }
+
+      public X _4() {
+        return f.f(P8.this._4());
+      }
+
+      public E _5() {
+        return P8.this._5();
+      }
+
+      public F _6() {
+        return P8.this._6();
+      }
+
+      public G _7() {
+        return P8.this._7();
+      }
+
+      public H _8() {
+        return P8.this._8();
+      }
+    };
+  }
+
+  /**
+   * Map the fifth element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P8<A, B, C, D, X, F, G, H> map5(final fj.F<E, X> f) {
+    return new P8<A, B, C, D, X, F, G, H>() {
+      public A _1() {
+        return P8.this._1();
+      }
+
+      public B _2() {
+        return P8.this._2();
+      }
+
+      public C _3() {
+        return P8.this._3();
+      }
+
+      public D _4() {
+        return P8.this._4();
+      }
+
+      public X _5() {
+        return f.f(P8.this._5());
+      }
+
+      public F _6() {
+        return P8.this._6();
+      }
+
+      public G _7() {
+        return P8.this._7();
+      }
+
+      public H _8() {
+        return P8.this._8();
+      }
+    };
+  }
+
+  /**
+   * Map the sixth element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P8<A, B, C, D, E, X, G, H> map6(final fj.F<F, X> f) {
+    return new P8<A, B, C, D, E, X, G, H>() {
+      public A _1() {
+        return P8.this._1();
+      }
+
+      public B _2() {
+        return P8.this._2();
+      }
+
+      public C _3() {
+        return P8.this._3();
+      }
+
+      public D _4() {
+        return P8.this._4();
+      }
+
+      public E _5() {
+        return P8.this._5();
+      }
+
+      public X _6() {
+        return f.f(P8.this._6());
+      }
+
+      public G _7() {
+        return P8.this._7();
+      }
+
+      public H _8() {
+        return P8.this._8();
+      }
+    };
+  }
+
+  /**
+   * Map the seventh element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P8<A, B, C, D, E, F, X, H> map7(final fj.F<G, X> f) {
+    return new P8<A, B, C, D, E, F, X, H>() {
+      public A _1() {
+        return P8.this._1();
+      }
+
+      public B _2() {
+        return P8.this._2();
+      }
+
+      public C _3() {
+        return P8.this._3();
+      }
+
+      public D _4() {
+        return P8.this._4();
+      }
+
+      public E _5() {
+        return P8.this._5();
+      }
+
+      public F _6() {
+        return P8.this._6();
+      }
+
+      public X _7() {
+        return f.f(P8.this._7());
+      }
+
+      public H _8() {
+        return P8.this._8();
+      }
+    };
+  }
+
+  /**
+   * Map the eighth element of the product.
+   *
+   * @param f The function to map with.
+   * @return A product with the given function applied.
+   */
+  public final <X> P8<A, B, C, D, E, F, G, X> map8(final fj.F<H, X> f) {
+    return new P8<A, B, C, D, E, F, G, X>() {
+      public A _1() {
+        return P8.this._1();
+      }
+
+      public B _2() {
+        return P8.this._2();
+      }
+
+      public C _3() {
+        return P8.this._3();
+      }
+
+      public D _4() {
+        return P8.this._4();
+      }
+
+      public E _5() {
+        return P8.this._5();
+      }
+
+      public F _6() {
+        return P8.this._6();
+      }
+
+      public G _7() {
+        return P8.this._7();
+      }
+
+      public X _8() {
+        return f.f(P8.this._8());
+      }
+    };
+  }
+
+
+  /**
+   * Returns the 1-product projection over the first element.
+   *
+   * @return the 1-product projection over the first element.
+   */
+  public final P1<A> _1_() {
+    return F1Functions.lazy(P8.<A, B, C, D, E, F, G, H>__1()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the second element.
+   *
+   * @return the 1-product projection over the second element.
+   */
+  public final P1<B> _2_() {
+    return F1Functions.lazy(P8.<A, B, C, D, E, F, G, H>__2()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the third element.
+   *
+   * @return the 1-product projection over the third element.
+   */
+  public final P1<C> _3_() {
+    return F1Functions.lazy(P8.<A, B, C, D, E, F, G, H>__3()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the fourth element.
+   *
+   * @return the 1-product projection over the fourth element.
+   */
+  public final P1<D> _4_() {
+    return F1Functions.lazy(P8.<A, B, C, D, E, F, G, H>__4()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the fifth element.
+   *
+   * @return the 1-product projection over the fifth element.
+   */
+  public final P1<E> _5_() {
+    return F1Functions.lazy(P8.<A, B, C, D, E, F, G, H>__5()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the sixth element.
+   *
+   * @return the 1-product projection over the sixth element.
+   */
+  public final P1<F> _6_() {
+    return F1Functions.lazy(P8.<A, B, C, D, E, F, G, H>__6()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the seventh element.
+   *
+   * @return the 1-product projection over the seventh element.
+   */
+  public final P1<G> _7_() {
+    return F1Functions.lazy(P8.<A, B, C, D, E, F, G, H>__7()).f(this);
+  }
+
+  /**
+   * Returns the 1-product projection over the eighth element.
+   *
+   * @return the 1-product projection over the eighth element.
+   */
+  public final P1<H> _8_() {
+    return F1Functions.lazy(P8.<A, B, C, D, E, F, G, H>__8()).f(this);
+  }
+
+  /**
+   * Provides a memoising P8 that remembers its values.
+   *
+   * @return A P8 that calls this P8 once for any given element and remembers the value for subsequent calls.
+   */
+  public final P8<A, B, C, D, E, F, G, H> memo() {
+      P8<A, B, C, D, E, F, G, H> self = this;
+    return new P8<A, B, C, D, E, F, G, H>() {
+      private final P1<A> a = P1.memo(u -> self._1());
+      private final P1<B> b = P1.memo(u -> self._2());
+      private final P1<C> c = P1.memo(u -> self._3());
+      private final P1<D> d = P1.memo(u -> self._4());
+      private final P1<E> e = P1.memo(u -> self._5());
+      private final P1<F> f = P1.memo(u -> self._6());
+      private final P1<G> g = P1.memo(u -> self._7());
+      private final P1<H> h = P1.memo(u -> self._8());
+
+      public A _1() {
+        return a._1();
+      }
+
+      public B _2() {
+        return b._1();
+      }
+
+      public C _3() {
+        return c._1();
+      }
+
+      public D _4() {
+        return d._1();
+      }
+
+      public E _5() {
+        return e._1();
+      }
+
+      public F _6() {
+        return f._1();
+      }
+
+      public G _7() {
+        return g._1();
+      }
+
+      public H _8() {
+        return h._1();
+      }
+    };
+  }
+
+
+  /**
+   * Returns a function that returns the first element of a product.
+   *
+   * @return A function that returns the first element of a product.
+   */
+  public static <A, B, C, D, E, F$, G, H> fj.F<P8<A, B, C, D, E, F$, G, H>, A> __1() {
+    return new fj.F<P8<A, B, C, D, E, F$, G, H>, A>() {
+      public A f(final P8<A, B, C, D, E, F$, G, H> p) {
+        return p._1();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the second element of a product.
+   *
+   * @return A function that returns the second element of a product.
+   */
+  public static <A, B, C, D, E, F$, G, H> fj.F<P8<A, B, C, D, E, F$, G, H>, B> __2() {
+    return new fj.F<P8<A, B, C, D, E, F$, G, H>, B>() {
+      public B f(final P8<A, B, C, D, E, F$, G, H> p) {
+        return p._2();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the third element of a product.
+   *
+   * @return A function that returns the third element of a product.
+   */
+  public static <A, B, C, D, E, F$, G, H> fj.F<P8<A, B, C, D, E, F$, G, H>, C> __3() {
+    return new fj.F<P8<A, B, C, D, E, F$, G, H>, C>() {
+      public C f(final P8<A, B, C, D, E, F$, G, H> p) {
+        return p._3();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the fourth element of a product.
+   *
+   * @return A function that returns the fourth element of a product.
+   */
+  public static <A, B, C, D, E, F$, G, H> fj.F<P8<A, B, C, D, E, F$, G, H>, D> __4() {
+    return new fj.F<P8<A, B, C, D, E, F$, G, H>, D>() {
+      public D f(final P8<A, B, C, D, E, F$, G, H> p) {
+        return p._4();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the fifth element of a product.
+   *
+   * @return A function that returns the fifth element of a product.
+   */
+  public static <A, B, C, D, E, F$, G, H> fj.F<P8<A, B, C, D, E, F$, G, H>, E> __5() {
+    return new fj.F<P8<A, B, C, D, E, F$, G, H>, E>() {
+      public E f(final P8<A, B, C, D, E, F$, G, H> p) {
+        return p._5();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the sixth element of a product.
+   *
+   * @return A function that returns the sixth element of a product.
+   */
+  public static <A, B, C, D, E, F$, G, H> fj.F<P8<A, B, C, D, E, F$, G, H>, F$> __6() {
+    return new fj.F<P8<A, B, C, D, E, F$, G, H>, F$>() {
+      public F$ f(final P8<A, B, C, D, E, F$, G, H> p) {
+        return p._6();
+      }
+    };
+  }
+
+  /**
+   * Returns a function that returns the seventh element of a product.
+   *
+   * @return A function that returns the seventh element of a product.
+   */