# HG changeset patch # User tatsuki # Date 1426853043 -32400 # Node ID fe80c1edf1be8bf032ce6b4058ffbad5a5009b85 add getLoop diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Bottom.java --- /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 P1 error_(final String s) { + return new P1() { + @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 F errorF(final String s) { + return new F() { + 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 Error decons(final A a, final Show 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 Error decons(final java.lang.Class c) { + return error("Deconstruction failure on type " + c); + } + + /** + * A function that returns the toString for a throwable. + * + * @return A function that returns the toString for a throwable. + */ + public static F eToString() { + return new F() { + public String f(final Throwable t) { + return t.toString(); + } + }; + } + + /** + * A function that returns the getMessage for a throwable. + * + * @return A function that returns the getMessage for a throwable. + */ + public static F eMessage() { + return new F() { + public String f(final Throwable t) { + return t.getMessage(); + } + }; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Class.java --- /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 { + private final java.lang.Class c; + + private Class(final java.lang.Class c) { + this.c = c; + } + + /** + * Returns the inheritance hierarchy of this class. + * + * @return The inheritance hierarchy of this class. + */ + public List> inheritance() { + return unfold( + new F, Option, java.lang.Class>>>() { + public Option, java.lang.Class>> f( + final java.lang.Class c) { + if (c == null) + return none(); + else { + final P2, java.lang.Class> p = + new P2, java.lang.Class>() { + public java.lang.Class _1() { + return c; + } + + @SuppressWarnings({"unchecked"}) + public java.lang.Class _2() { + return c.getSuperclass(); + } + }; + return some(p); + } + } + }, c).map(new F, Class>() { + public Class f(final java.lang.Class 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 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 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> interfaceParameters() { + List> 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 typeParameterTree(final Type t) { + List> typeArgs = List.nil(); + final Tree 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.>nil()); + } + return types; + } + + /** + * Returns the underlying class. + * + * @return The underlying class. + */ + public java.lang.Class 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 Class clas(final java.lang.Class c) { + return new Class(c); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Digit.java --- /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 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 toLong = new F() { + public Long f(final Digit d) { + return d.toLong(); + } + }; + + /** + * First-class conversion from a long to a digit. + */ + public static final F fromLong = new F() { + public Digit f(final Long i) { + return fromLong(i); + } + }; + + /** + * First-class conversion from a digit to a character. + */ + public static final F toChar = new F() { + public Character f(final Digit d) { + return d.toChar(); + } + }; + + /** + * First-class conversion from a character to a digit. + */ + public static final F> fromChar = new F>() { + public Option f(final Character c) { + return fromChar(c); + } + }; +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Effect.java --- /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 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 F f(Effect1 e1) { + return a -> { + e1.f(a); + return unit(); + }; + } + + public static F2 f(Effect2 e) { + return (a, b) -> { + e.f(a, b); + return unit(); + }; + } + + public static F3 f(Effect3 e) { + return (a, b, c) -> { + e.f(a, b, c); + return unit(); + }; + } + + public static F4 f(Effect4 e) { + return (a, b, c, d) -> { + e.f(a, b, c, d); + return unit(); + }; + } + + public static F5 f(Effect5 z) { + return (a, b, c, d, e) -> { + z.f(a, b, c, d, e); + return unit(); + }; + } + + public static F6 f(Effect6 z) { + return (a, b, c, d, e, f) -> { + z.f(a, b, c, d, e, f); + return unit(); + }; + } + + public static F7 f(Effect7 z) { + return (a, b, c, d, e, f, g) -> { + z.f(a, b, c, d, e, f, g); + return unit(); + }; + } + + public static F8 f(Effect8 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 Effect1 comap(Effect1 e1, final F f) { + return new Effect1() { + public void f(final B b) { + e1.f(f.f(b)); + } + }; + } + + public static Effect1 lazy(final F f) { + return new Effect1() { + public void f(final A a) { + f.f(a); + } + }; + } + +// public static void f(Effect1 ) + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Equal.java --- /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 { + private final F> f; + + private Equal(final F> f) { + this.f = f; + } + + /** + * Returns true if the two given arguments are equal, false otherwise. + * + * @param a1 An object to test for equality against another. + * @param a2 An object to test for equality against another. + * @return true if the two given arguments are equal, false 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 true if the two given arguments are equal. + */ + public F2 eq() { + return new F2() { + 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 true if the given argument equals the argument to this method. + */ + public F eq(final A a) { + return new F() { + 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 Equal comap(final F f) { + return equal(F1Functions.o(F1Functions.o(F1Functions.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 Equal equal(final F> f) { + return new Equal(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 Equal anyEqual() { + return new Equal(new F>() { + public F f(final A a1) { + return new F() { + public Boolean f(final A a2) { + return a1.equals(a2); + } + }; + } + }); + } + + /** + * An equal instance for the boolean type. + */ + public static final Equal booleanEqual = anyEqual(); + + /** + * An equal instance for the byte type. + */ + public static final Equal byteEqual = anyEqual(); + + /** + * An equal instance for the char type. + */ + public static final Equal charEqual = anyEqual(); + + /** + * An equal instance for the double type. + */ + public static final Equal doubleEqual = anyEqual(); + + /** + * An equal instance for the float type. + */ + public static final Equal floatEqual = anyEqual(); + + /** + * An equal instance for the int type. + */ + public static final Equal intEqual = anyEqual(); + + /** + * An equal instance for the BigInteger type. + */ + public static final Equal bigintEqual = anyEqual(); + + /** + * An equal instance for the BigDecimal type. + */ + public static final Equal bigdecimalEqual = anyEqual(); + + /** + * An equal instance for the long type. + */ + public static final Equal longEqual = anyEqual(); + + /** + * An equal instance for the short type. + */ + public static final Equal shortEqual = anyEqual(); + + /** + * An equal instance for the {@link String} type. + */ + public static final Equal stringEqual = anyEqual(); + + /** + * An equal instance for the {@link StringBuffer} type. + */ + public static final Equal stringBufferEqual = + new Equal(new F>() { + public F f(final StringBuffer sb1) { + return new F() { + 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 stringBuilderEqual = + new Equal(new F>() { + public F f(final StringBuilder sb1) { + return new F() { + 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 Equal> eitherEqual(final Equal ea, final Equal eb) { + return new Equal>(new F, F, Boolean>>() { + public F, Boolean> f(final Either e1) { + return new F, Boolean>() { + public Boolean f(final Either 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 Equal> validationEqual(final Equal ea, final Equal eb) { + return eitherEqual(ea, eb).comap(Validation.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 Equal> listEqual(final Equal ea) { + return new Equal>(new F, F, Boolean>>() { + public F, Boolean> f(final List a1) { + return new F, Boolean>() { + public Boolean f(final List a2) { + List x1 = a1; + List 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 Equal> nonEmptyListEqual(final Equal ea) { + return listEqual(ea).comap(NonEmptyList.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 Equal> optionEqual(final Equal ea) { + return new Equal>(new F, F, Boolean>>() { + public F, Boolean> f(final Option o1) { + return new F, Boolean>() { + public Boolean f(final Option 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 Equal> streamEqual(final Equal ea) { + return new Equal>(new F, F, Boolean>>() { + public F, Boolean> f(final Stream a1) { + return new F, Boolean>() { + public Boolean f(final Stream a2) { + Stream x1 = a1; + Stream 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 Equal> arrayEqual(final Equal ea) { + return new Equal>(new F, F, Boolean>>() { + public F, Boolean> f(final Array a1) { + return new F, Boolean>() { + public Boolean f(final Array 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 Equal> treeEqual(final Equal ea) { + return new Equal>(curry(new F2, Tree, Boolean>() { + public Boolean f(final Tree t1, final Tree 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 Equal> p1Equal(final Equal ea) { + return new Equal>(new F, F, Boolean>>() { + public F, Boolean> f(final P1 p1) { + return new F, Boolean>() { + public Boolean f(final P1 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 Equal> p2Equal(final Equal ea, final Equal eb) { + return new Equal>(new F, F, Boolean>>() { + public F, Boolean> f(final P2 p1) { + return new F, Boolean>() { + public Boolean f(final P2 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 Equal> p3Equal(final Equal ea, final Equal eb, final Equal ec) { + return new Equal>(new F, F, Boolean>>() { + public F, Boolean> f(final P3 p1) { + return new F, Boolean>() { + public Boolean f(final P3 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 Equal> p4Equal(final Equal ea, final Equal eb, final Equal ec, + final Equal ed) { + return new Equal>(new F, F, Boolean>>() { + public F, Boolean> f(final P4 p1) { + return new F, Boolean>() { + public Boolean f(final P4 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 Equal> p5Equal(final Equal ea, final Equal eb, + final Equal ec, final Equal ed, + final Equal ee) { + return new Equal>(new F, F, Boolean>>() { + public F, Boolean> f(final P5 p1) { + return new F, Boolean>() { + public Boolean f(final P5 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 Equal> p6Equal(final Equal ea, final Equal eb, + final Equal ec, final Equal ed, + final Equal ee, final Equal ef) { + return new Equal>(new F, F, Boolean>>() { + public F, Boolean> f(final P6 p1) { + return new F, Boolean>() { + public Boolean f(final P6 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 Equal> p7Equal(final Equal ea, final Equal eb, + final Equal ec, final Equal ed, + final Equal ee, final Equal ef, + final Equal eg) { + return new Equal>(new F, F, Boolean>>() { + public F, Boolean> f(final P7 p1) { + return new F, Boolean>() { + public Boolean f(final P7 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 Equal> p8Equal(final Equal ea, + final Equal eb, + final Equal ec, + final Equal ed, + final Equal ee, + final Equal ef, + final Equal eg, + final Equal eh) { + return new Equal>( + new F, F, Boolean>>() { + public F, Boolean> f(final P8 p1) { + return new F, Boolean>() { + public Boolean f(final P8 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 Equal> v2Equal(final Equal ea) { + return streamEqual(ea).comap(V2.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 Equal> v3Equal(final Equal ea) { + return streamEqual(ea).comap(V3.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 Equal> v4Equal(final Equal ea) { + return streamEqual(ea).comap(V4.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 Equal> v5Equal(final Equal ea) { + return streamEqual(ea).comap(V5.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 Equal> v6Equal(final Equal ea) { + return streamEqual(ea).comap(V6.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 Equal> v7Equal(final Equal ea) { + return streamEqual(ea).comap(V7.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 Equal> v8Equal(final Equal ea) { + return streamEqual(ea).comap(V8.toStream_()); + } + + /** + * An equal instance for lazy strings. + */ + public static final Equal eq = streamEqual(charEqual).comap(LazyString.toStream); + + /** + * An equal instance for the empty heterogeneous list. + */ + public static final Equal 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 > Equal> hListEqual(final Equal e, final Equal l) { + return equal(curry(new F2, HList.HCons, Boolean>() { + public Boolean f(final HList.HCons c1, final HList.HCons 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 Equal> setEqual(final Equal e) { + return equal(curry(new F2, Set, Boolean>() { + public Boolean f(final Set a, final Set b) { + return streamEqual(e).eq(a.toStream(), b.toStream()); + } + })); + } + + public static Equal> writerEqual(Equal eq1, Equal eq2) { + return new Equal>(w1 -> w2 -> Equal.p2Equal(eq1, eq2).eq(w1.run(), w2.run())); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F.java --- /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 A to B. This type can be represented + * using the Java 7 closure syntax. + * + * @version %build.number% + */ +public interface F { + /** + * Transform A to B. + * + * @param a The A to transform. + * @return The result of the transformation. + */ + public abstract B f(A a); + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F1Functions.java --- /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 F o(final F f, final F g) { + return new F() { + 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 F, F> o(final F f) { + return new F, F>() { + public F f(final F 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 F andThen(final F f, final F 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 F, F> andThen(final F f) { + return new F, F>() { + public F f(final F 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 F bind(final F f, final F> g) { + return new F() { + @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 F>, F> bind(final F f) { + return new F>, F>() { + public F f(final F> 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 F apply(final F f, final F> g) { + return new F() { + @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 F>, F> apply(final F f) { + return new F>, F>() { + public F f(final F> 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 F> on(final F f, final F> g) { + return new F>() { + public F f(final A a1) { + return new F() { + @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 F>, F>> on(final F f) { + return new F>, F>>() { + public F> f(final F> 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 F> lazy(final F f) { + return new F>() { + public P1 f(final A a) { + return new P1() { + public B _1() { + return f.f(a); + } + }; + } + }; + } + + /** + * Partial application. + * + * @param a The A to which to apply this function. + * @return The function partially applied to the given argument to return a lazy value. + */ + static public P1 f(final F 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 F, P1> mapP1(final F f) { + return new F, P1>() { + public P1 f(final P1 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 F> optionK(final F f) { + return new F>() { + public Option 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 F, Option> mapOption(final F f) { + return new F, Option>() { + public Option f(final Option 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 F> listK(final F f) { + return new F>() { + public List 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 F, List> mapList(final F f) { + return new F, List>() { + public List f(final List 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 F> streamK(final F f) { + return new F>() { + public Stream 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 F, Stream> mapStream(final F f) { + return new F, Stream>() { + public Stream f(final Stream 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 F> arrayK(final F f) { + return new F>() { + public Array 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 F, Array> mapArray(final F f) { + return new F, Array>() { + public Array f(final Array 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 F, Actor> comapActor(final F f) { + return new F, Actor>() { + public Actor f(final Actor 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 F> promiseK(final F f, final Strategy s) { + return Promise.promise(s, f); + } + + /** + * Promotes this function to map over a Promise. + * + * @return This function promoted to map over Promises. + */ + static public F, Promise> mapPromise(final F f) { + return new F, Promise>() { + public Promise f(final Promise 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 F> eitherLeftK(final F f) { + return o(Either.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 F> eitherRightK(final F f) { + return o(Either.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 F, Either> mapLeft(final F f) { + return Either.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 F, Either> mapRight(final F f) { + return Either.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 F, B> onLeft(final F f) { + return new F, B>() { + public B f(final Either 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 F, B> onRight(final F f) { + return new F, B>() { + public B f(final Either 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 F> iterableK(final F f) { + return IterableW.arrow().f(f); + } + + /** + * Promotes this function to map over Iterables. + * + * @return This function promoted to map over Iterables. + */ + @SuppressWarnings({"unchecked"}) + static public F, IterableW> mapIterable(final F f) { + return F1Functions.o(IterableW.map().f(f), IterableW.>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 F> nelK(final F f) { + return o(NonEmptyList.nel(), f); + } + + /** + * Promotes this function to map over a NonEmptyList. + * + * @return This function promoted to map over a NonEmptyList. + */ + static public F, NonEmptyList> mapNel(final F f) { + return new F, NonEmptyList>() { + public NonEmptyList f(final NonEmptyList 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 F> setK(final F f, final Ord o + ) { + return new F>() { + public Set 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 F, Set> mapSet(final F f, final Ord o) { + return new F, Set>() { + public Set f(final Set 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 F> treeK(final F f) { + return new F>() { + public Tree 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 F, Tree> mapTree(final F f) { + return Tree.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 F, B> foldMapTree(final F f, final Monoid 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 F> treeZipperK(final F f) { + return andThen(treeK(f), TreeZipper.fromTree()); + } + + /** + * Promotes this function to map over a TreeZipper. + * + * @return This function promoted to map over a TreeZipper. + */ + static public F, TreeZipper> mapTreeZipper(final F f) { + return new F, TreeZipper>() { + public TreeZipper f(final TreeZipper 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 F> failK(final F f) { + return new F>() { + public Validation 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 F> successK(final F f) { + return new F>() { + public Validation 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 F, Validation> mapFail(final F f) { + return new F, Validation>() { + public Validation f(final Validation 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 F, Validation> mapSuccess(final F f) { + return new F, Validation>() { + public Validation f(final Validation 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 F, B> onFail(final F f) { + return new F, B>() { + public B f(final Validation 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 F, B> onSuccess(final F f) { + return new F, B>() { + public B f(final Validation 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 F> zipperK(final F f) { + return andThen(streamK(f), new F, Zipper>() { + public Zipper f(final Stream stream) { + return fromStream(stream).some(); + } + }); + } + + /** + * Promotes this function to map over a Zipper. + * + * @return This function promoted to map over a Zipper. + */ + static public F, Zipper> mapZipper(final F f) { + return new F, Zipper>() { + public Zipper f(final Zipper 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 F, Equal> comapEqual(final F f) { + return new F, Equal>() { + public Equal f(final Equal 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 F, Hash> comapHash(final F f) { + return new F, Hash>() { + public Hash f(final Hash 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 F, Show> comapShow(final F f) { + return new F, Show>() { + public Show f(final Show 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 F, P2> mapFst(final F 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 F, P2> mapSnd(final F 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 F, P2> mapBoth(final F f) { + return new F, P2>() { + public P2 f(final P2 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 SynchronousQueue mapJ(final F f, final SynchronousQueue as) { + final SynchronousQueue bs = new SynchronousQueue(); + 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 PriorityBlockingQueue mapJ(final F f, final PriorityBlockingQueue as) { + return new PriorityBlockingQueue(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 LinkedBlockingQueue mapJ(final F f, final LinkedBlockingQueue as) { + return new LinkedBlockingQueue(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 CopyOnWriteArraySet mapJ(final F f, final CopyOnWriteArraySet as) { + return new CopyOnWriteArraySet(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 CopyOnWriteArrayList mapJ(final F f, final CopyOnWriteArrayList as) { + return new CopyOnWriteArrayList(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 ConcurrentLinkedQueue mapJ(final F f, final ConcurrentLinkedQueue as) { + return new ConcurrentLinkedQueue(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 ArrayBlockingQueue mapJ(final F f, final ArrayBlockingQueue as) { + final ArrayBlockingQueue bs = new ArrayBlockingQueue(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 TreeSet mapJ(final F f, final TreeSet as) { + return new TreeSet(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 PriorityQueue mapJ(final F f, final PriorityQueue as) { + return new PriorityQueue(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 LinkedList mapJ(final F f, final LinkedList as) { + return new LinkedList(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 ArrayList mapJ(final F f, final ArrayList as) { + return new ArrayList(iterableStream(as).map(f).toCollection()); + } + + static public F map(F target, F f) { + return andThen(target, f); + } + + static public F contramap(F target, F f) { + return andThen(f, target); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F2.java --- /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 A and B to C. + * This type can be represented using the Java 7 closure syntax. + * + * @version %build.number% + */ +public interface F2 { + /** + * Transform A and B to C. + * + * @param a The A to transform. + * @param b The B to transform. + * @return The result of the transformation. + */ + public C f(A a, B b); + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F2Functions.java --- /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 A to which to apply this function. + * @return The function partially applied to the given argument. + */ + static public F f(final F2 f, final A a) { + return new F() { + 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 F> curry(final F2 f) { + return new F>() { + public F f(final A a) { + return new F() { + 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 F2 flip(final F2 f) { + return new F2() { + 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 F, C> tuple(final F2 f) { + return new F, C>() { + public C f(final P2 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 F2, Array, Array> arrayM(final F2 f) { + return new F2, Array, Array>() { + public Array f(final Array a, final Array b) { + return a.bind(b, curry(f)); + } + }; + } + + /** + * Promotes this function to a function on Promises. + * + * @return This function promoted to transform Promises. + */ + static public F2, Promise, Promise> promiseM(final F2 f) { + return new F2, Promise, Promise>() { + public Promise f(final Promise a, final Promise b) { + return a.bind(b, curry(f)); + } + }; + } + + /** + * Promotes this function to a function on Iterables. + * + * @return This function promoted to transform Iterables. + */ + static public F2, Iterable, IterableW> iterableM(final F2 f) { + return new F2, Iterable, IterableW>() { + public IterableW f(final Iterable a, final Iterable 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 F2, List, List> listM(final F2 f) { + return new F2, List, List>() { + public List f(final List a, final List 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 F2, NonEmptyList, NonEmptyList> nelM(final F2 f) { + return new F2, NonEmptyList, NonEmptyList>() { + public NonEmptyList f(final NonEmptyList as, final NonEmptyList 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 F2, Option, Option> optionM(final F2 f) { + return new F2, Option, Option>() { + public Option f(final Option a, final Option 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 F2, Set, Set> setM(final F2 f, final Ord o) { + return new F2, Set, Set>() { + public Set f(final Set as, final Set bs) { + Set 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 F2, Stream, Stream> streamM(final F2 f) { + return new F2, Stream, Stream>() { + public Stream f(final Stream as, final Stream bs) { + return as.bind(bs, f); + } + }; + } + + /** + * Promotes this function to a function on Trees. + * + * @return This function promoted to transform Trees. + */ + static public F2, Tree, Tree> treeM(final F2 f) { + return new F2, Tree, Tree>() { + public Tree f(final Tree as, final Tree bs) { + final F2, Tree, Tree> self = this; + return node(f.f(as.root(), bs.root()), new P1>>() { + public Stream> _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 F2, Array, Array> zipArrayM(final F2 f) { + return new F2, Array, Array>() { + public Array f(final Array as, final Array 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 F2, Iterable, Iterable> zipIterableM(final F2 f) { + return new F2, Iterable, Iterable>() { + public Iterable f(final Iterable as, final Iterable 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 F2, List, List> zipListM(final F2 f) { + return new F2, List, List>() { + public List f(final List as, final List 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 F2, Stream, Stream> zipStreamM(final F2 f) { + return new F2, Stream, Stream>() { + public Stream f(final Stream as, final Stream 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 F2, NonEmptyList, NonEmptyList> zipNelM(final F2 f) { + return new F2, NonEmptyList, NonEmptyList>() { + public NonEmptyList f(final NonEmptyList as, final NonEmptyList 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 F2, Set, Set> zipSetM(final F2 f, final Ord o) { + return new F2, Set, Set>() { + public Set f(final Set as, final Set 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 F2, Tree, Tree> zipTreeM(final F2 f) { + return new F2, Tree, Tree>() { + public Tree f(final Tree ta, final Tree tb) { + final F2, Tree, Tree> self = this; + return node(f.f(ta.root(), tb.root()), new P1>>() { + public Stream> _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 F2, Zipper, Zipper> zipZipperM(final F2 f) { + return new F2, Zipper, Zipper>() { + @SuppressWarnings({"unchecked"}) + public Zipper f(final Zipper ta, final Zipper tb) { + final F2, Stream, Stream> 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 F2, TreeZipper, TreeZipper> zipTreeZipperM(final F2 f) { + return new F2, TreeZipper, TreeZipper>() { + @SuppressWarnings({"unchecked"}) + public TreeZipper f(final TreeZipper ta, final TreeZipper tb) { + final F2>, Stream>, Stream>> sf = zipStreamM(treeM(f)); + final + F2>, A, Stream>>>, + Stream>, B, Stream>>>, + Stream>, C, Stream>>>> + pf = + zipStreamM(new F2>, A, Stream>>, + P3>, B, Stream>>, + P3>, C, Stream>>>() { + public P3>, C, Stream>> f(final P3>, A, Stream>> pa, + final P3>, B, Stream>> 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 F2 contramapFirst(F2 target, F f) { + return (z, b) -> target.f(f.f(z), b); + } + + static public F2 contramapSecond(F2 target, F f) { + return (a, z) -> target.f(a, f.f(z)); + } + + static public F2 contramap(F2 target, F f, F g) { + return contramapSecond(contramapFirst(target, f), g); + } + + static public F2 map(F2 target, F f) { + return (a, b) -> f.f(target.f(a, b)); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F3.java --- /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 A, B and C to + * D. This type can be represented using the Java 7 closure syntax. + * + * @version %build.number% + */ +public interface F3 { + /** + * Transform A, B and C to D. + * + * @param a The A to transform. + * @param b The B to transform. + * @param c The C to transform. + * @return The result of the transformation. + */ + public D f(A a, B b, C c); +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F3Functions.java --- /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 A to which to apply this function. + * @return The function partially applied to the given argument. + */ + static public F2 f(final F3 f, final A a) { + return (b, c) -> f.f(a, b, c); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F4.java --- /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 A, B, C and + * D to E. This type can be represented using the Java 7 closure syntax. + * + * @version %build.number% + */ +public interface F4 { + /** + * Transform A, B, C and D to E. + * + * @param a The A to transform. + * @param b The B to transform. + * @param c The C to transform. + * @param d The D to transform. + * @return The result of the transformation. + */ + public E f(A a, B b, C c, D d); +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F4Functions.java --- /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 A to which to apply this function. + * @return The function partially applied to the given argument. + */ + static public F3 f(final F4 f, final A a) { + return (b, c, d) -> f.f(a, b, c, d); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F5.java --- /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 A, B, C, + * D and E to F$. This type can be represented using the Java + * 7 closure syntax. + * + * @version %build.number% + */ +public interface F5 { + /** + * Transform A, B, C, D and E to + * F$. + * + * @param a The A to transform. + * @param b The B to transform. + * @param c The C to transform. + * @param d The D to transform. + * @param e The E to transform. + * @return The result of the transformation. + */ + public F$ f(A a, B b, C c, D d, E e); +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F5Functions.java --- /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 A to which to apply this function. + * @return The function partially applied to the given argument. + */ + static public F4 f(final F5 f, final A a) { + return (b, c, d, e) -> f.f(a, b, c, d, e); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F6.java --- /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 A, B, C, + * D, E and F$ to G. This type can be + * represented using the Java 7 closure syntax. + * + * @version %build.number% + */ +public interface F6 { + /** + * Transform A, B, C, D, E and + * F$ to G. + * + * @param a The A to transform. + * @param b The B to transform. + * @param c The C to transform. + * @param d The D to transform. + * @param e The E to transform. + * @param f The F$ to transform. + * @return The result of the transformation. + */ + public G f(A a, B b, C c, D d, E e, F$ f); +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F6Functions.java --- /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 A to which to apply this function. + * @return The function partially applied to the given argument. + */ + static public F5 f(final F6 func, final A a) { + return (b, c, d, e, f) -> func.f(a, b, c, d, e, f); + } + + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F7.java --- /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 A, B, C, + * D, E, F$ and G to H. This type + * can be represented using the Java 7 closure syntax. + * + * @version %build.number% + */ +public interface F7 { + /** + * Transform A, B, C, D, E, + * F$ and G to H. + * + * @param a The A to transform. + * @param b The B to transform. + * @param c The C to transform. + * @param d The D to transform. + * @param e The E to transform. + * @param f The F$ to transform. + * @param g The G 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); +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F7Functions.java --- /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 A to which to apply this function. + * @return The function partially applied to the given argument. + */ + static public F6 f(final F7 func, final A a) { + return (b, c, d, e, f, g) -> func.f(a, b, c, d, e, f, g); + } + + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F8.java --- /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 A, B, C, + * D, E, F$, G and H to + * I. This type can be represented using the Java 7 closure syntax. + * + * @version %build.number% + */ +public interface F8 { + /** + * Transform A, B, C, D, E, + * F$, G and H to I. + * + * @param a The A to transform. + * @param b The B to transform. + * @param c The C to transform. + * @param d The D to transform. + * @param e The E to transform. + * @param f The F$ to transform. + * @param g The G to transform. + * @param h The H 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); +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/F8Functions.java --- /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 A to which to apply this function. + * @return The function partially applied to the given argument. + */ + static public F7 f(final F8 func, final A a) { + return (b, c, d, e, f, g, h) -> func.f(a, b, c, d, e, f, g, h); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Function.java --- /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 F, B> apply(final A a) { + return new F, B>() { + public B f(final F k) { + return k.f(a); + } + }; + } + + /** + * Function composition. + * + * @return A function that composes two functions to produce a new function. + */ + public static F, F, F>> compose() { + return new F, F, F>>() { + public F, F> f(final F f) { + return new F, F>() { + public F f(final F 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 F compose(final F f, final F g) { + return new F() { + 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 F> compose2(final F f, final F> g) { + return new F>() { + public F f(final A a) { + return new F() { + 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 F, F, F>> andThen() { + return new F, F, F>>() { + public F, F> f(final F g) { + return new F, F>() { + public F f(final F 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 F andThen(final F g, final F f) { + return new F() { + public C f(final A a) { + return f.f(g.f(a)); + } + }; + } + + /** + * The identity transformation. + * + * @return The identity transformation. + */ + public static F identity() { + return new F() { + 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 F> constant() { + return new F>() { + public F 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 F constant(final B b) { + return new F() { + 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 F vary(final F f) { + return new F() { + 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 F, F> vary() { + return new F, F>() { + public F f(final F f) { + return Function.vary(f); + } + }; + } + + /** + * Function argument flipping. + * + * @return A function that takes a function and flips its arguments. + */ + public static F>, F>> flip() { + return new F>, F>>() { + public F> f(final F> f) { + return flip(f); + } + }; + } + + /** + * Function argument flipping. + * + * @param f The function to flip. + * @return The given function flipped. + */ + public static F> flip(final F> f) { + return new F>() { + public F f(final B b) { + return new F() { + 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 F2 flip(final F2 f) { + return new F2() { + 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 F, F2> flip2() { + return new F, F2>() { + public F2 f(final F2 f) { + return flip(f); + } + }; + } + + /** + * Return a function that inspects the argument of the given function for a null value and if so, does + * not apply the value, instead returning an empty optional value. + * + * @param f The function to check for a null argument. + * @return A function that inspects the argument of the given function for a null value and if so, does + * not apply the value, instead returning an empty optional value. + */ + public static F> nullable(final F f) { + return new F>() { + public Option f(final A a) { + return a == null ? Option.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 F> curry(final F2 f) { + return new F>() { + public F f(final A a) { + return new F() { + 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 F curry(final F2 f, final A a) { + return curry(f).f(a); + } + + /** + * Uncurry a function of arity-2. + * + * @return An uncurried function. + */ + public static F>, F2> uncurryF2() { + return new F>, F2>() { + public F2 f(final F> f) { + return uncurryF2(f); + } + }; + } + + /** + * Uncurry a function of arity-2. + * + * @param f The function to uncurry. + * @return An uncurried function. + */ + public static F2 uncurryF2(final F> f) { + return new F2() { + 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 F>> curry(final F3 f) { + return new F>>() { + public F> f(final A a) { + return new F>() { + public F f(final B b) { + return new F() { + 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 F> curry(final F3 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 F curry(final F3 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 F>>, F3> uncurryF3() { + return new F>>, F3>() { + public F3 f(final F>> f) { + return uncurryF3(f); + } + }; + } + + /** + * Uncurry a function of arity-3. + * + * @param f The function to uncurry. + * @return An uncurried function. + */ + public static F3 uncurryF3(final F>> f) { + return new F3() { + 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 F>>> curry(final F4 f) { + return new F>>>() { + public F>> f(final A a) { + return new F>>() { + public F> f(final B b) { + return new F>() { + public F f(final C c) { + return new F() { + public 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 F>> curry(final F4 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 F> curry(final F4 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 F curry(final F4 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 F>>>, F4> uncurryF4() { + return new F>>>, F4>() { + public F4 f(final F>>> f) { + return uncurryF4(f); + } + }; + } + + /** + * Uncurry a function of arity-4. + * + * @param f The function to uncurry. + * @return An uncurried function. + */ + public static F4 uncurryF4(final F>>> f) { + return new F4() { + 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 F>>>> curry(final F5 f) { + return new F>>>>() { + public F>>> f(final A a) { + return new F>>>() { + public F>> f(final B b) { + return new F>>() { + public F> f(final C c) { + return new F>() { + public F f(final D d) { + return new F() { + public F$ f(final E e) { + return 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 F>>> curry(final F5 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 F>> curry(final F5 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 F> curry(final F5 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 F curry(final F5 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 F>>>>, F5> uncurryF5() { + return new F>>>>, F5>() { + public F5 f(final F>>>> f) { + return uncurryF5(f); + } + }; + } + + /** + * Uncurry a function of arity-6. + * + * @param f The function to uncurry. + * @return An uncurried function. + */ + public static F5 uncurryF5(final F>>>> f) { + return new F5() { + 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 F>>>>> curry(final F6 f) { + return new F>>>>>() { + public F>>>> f(final A a) { + return new F>>>>() { + public F>>> f(final B b) { + return new F>>>() { + public F>> f(final C c) { + return new F>>() { + public F> f(final D d) { + return new F>() { + public F f(final E e) { + return new F() { + public 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 F>>>>>, F6> uncurryF6() { + return new F>>>>>, F6>() { + public F6 f(final F>>>>> f) { + return uncurryF6(f); + } + }; + } + + /** + * Uncurry a function of arity-6. + * + * @param f The function to uncurry. + * @return An uncurried function. + */ + public static F6 uncurryF6( + final F>>>>> f) { + return new F6() { + 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 F>>>>>> curry( + final F7 f) { + return new F>>>>>>() { + public F>>>>> f(final A a) { + return new F>>>>>() { + public F>>>> f(final B b) { + return new F>>>>() { + public F>>> f(final C c) { + return new F>>>() { + public F>> f(final D d) { + return new F>>() { + public F> f(final E e) { + return new F>() { + public F f(final F$ f$) { + return new F() { + public 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 F>>>>> curry( + final F7 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 F>>>> curry(final F7 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 F>>> curry(final F7 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 F>> curry(final F7 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 F> curry(final F7 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 F curry(final F7 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 F>>>>>>, F7> uncurryF7() { + return new F>>>>>>, F7>() { + public F7 f(final F>>>>>> f) { + return uncurryF7(f); + } + }; + } + + /** + * Uncurry a function of arity-7. + * + * @param f The function to uncurry. + * @return An uncurried function. + */ + public static F7 uncurryF7( + final F>>>>>> f) { + return new F7() { + 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 F>>>>>>> curry( + final F8 f) { + return new F>>>>>>>() { + public F>>>>>> f(final A a) { + return new F>>>>>>() { + public F>>>>> f(final B b) { + return new F>>>>>() { + public F>>>> f(final C c) { + return new F>>>>() { + public F>>> f(final D d) { + return new F>>>() { + public F>> f(final E e) { + return new F>>() { + public F> f(final F$ f$) { + return new F>() { + public F f(final G g) { + return new F() { + public 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 F>>>>>> curry( + final F8 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 F>>>>> curry( + final F8 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 F>>>> curry( + final F8 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 F>>> curry(final F8 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 F>> curry(final F8 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 F> curry(final F8 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 F curry(final F8 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 F>>>>>>>, F8> uncurryF8() { + return new F>>>>>>>, F8>() { + public F8 f(final F>>>>>>> f) { + return uncurryF8(f); + } + }; + } + + /** + * Uncurry a function of arity-8. + * + * @param f The function to uncurry. + * @return An uncurried function. + */ + public static F8 uncurryF8( + final F>>>>>>> f) { + return new F8() { + 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 ma, + * and yields the return value. + * @return A function that chains the given functions together such that the result of applying + * ma to the argument is given to f, yielding a function + * that is applied to the argument again. + */ + public static F bind(final F ma, final F> f) { + return new F() { + 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 F apply(final F> cab, final F ca) { + return bind(cab, new F, F>() { + public F f(final F f) { + return compose(new F() { + public B f(final A a) { + return f.f(a); + } + }, ca); + } + }); + } + + /** + * Binds the given function f to the values of the given functions, with a final join. + * + * @param ca A function to bind f function to. + * @param cb A function to bind f function to. + * @param f The bound function to be composed with ca and then applied with cb + * @return A new function after performing the composition, then application. + */ + public static F bind(final F ca, final F cb, final F> 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 F> on(final F> a, final F f) { + return compose(compose(Function.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 F, F, F>> lift(final F> f) { + return curry(new F2, F, F>() { + public F f(final F ca, final F 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 f. + */ + public static F join(final F> f) { + return bind(f, Function.>identity()); + } + + + /** + * Partial application of the second argument to the supplied function to get a function of type + * A -> C. Same as flip(f).f(b). + * + * @param f The function to partially apply. + * @param b The value to apply to the function. + * @return A new function based on f with its second argument applied. + */ + public static F partialApply2(final F> f, final B b) { + return new F() { + 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 + * A -> B -> D. + * + * @param f The function to partially apply. + * @param c The value to apply to the function. + * @return A new function based on f with its third argument applied. + */ + public static F> partialApply3(final F>> f, final C c) { + return new F>() { + public F f(final A a) { + return new F() { + 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 + * A -> B -> C -> E. + * + * @param f The function to partially apply. + * @param d The value to apply to the function. + * @return A new function based on f with its fourth argument applied. + */ + public static F>> partialApply4(final F>>> f, final D d) { + return new F>>() { + public F> f(final A a) { + return new F>() { + public F f(final B b) { + return new F() { + 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 + * A -> B -> C -> D -> F$. + * + * @param f The function to partially apply. + * @param e The value to apply to the function. + * @return A new function based on f with its fifth argument applied. + */ + public static F>>> partialApply5(final F>>>> f, + final E e) { + return new F>>>() { + public F>> f(final A a) { + return new F>>() { + public F> f(final B b) { + return new F>() { + public F f(final C c) { + return new F() { + public F$ f(final D d) { + return uncurryF5(f).f(a, b, c, d, e); + } + }; + } + }; + } + }; + } + }; + } + + /** + * Partial application of the sixth argument to the supplied function to get a function of type + * A -> B -> C -> D -> E -> G. + * + * @param f The function to partially apply. + * @param f$ The value to apply to the function. + * @return A new function based on f with its sixth argument applied. + */ + public static F>>>> partialApply6( + final F>>>>> f, final F$ f$) { + return new F>>>>() { + public F>>> f(final A a) { + return new F>>>() { + public F>> f(final B b) { + return new F>>() { + public F> f(final C c) { + return new F>() { + public F f(final D d) { + return new F() { + public 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 + * A -> B -> C -> D -> E -> F$ -> H. + * + * @param f The function to partially apply. + * @param g The value to apply to the function. + * @return A new function based on f with its seventh argument applied. + */ + public static F>>>>> partialApply7( + final F>>>>>> f, final G g) { + return new F>>>>>() { + public F>>>> f(final A a) { + return new F>>>>() { + public F>>> f(final B b) { + return new F>>>() { + public F>> f(final C c) { + return new F>>() { + public F> f(final D d) { + return new F>() { + public F f(final E e) { + return new F() { + public 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 + * A -> B -> C -> D -> E -> F$ -> G -> I. + * + * @param f The function to partially apply. + * @param h The value to apply to the function. + * @return A new function based on f with its eigth argument applied. + */ + public static F>>>>>> partialApply8( + final F>>>>>>> f, final H h) { + return new F>>>>>>() { + public F>>>>> f(final A a) { + return new F>>>>>() { + public F>>>> f(final B b) { + return new F>>>>() { + public F>>> f(final C c) { + return new F>>>() { + public F>> f(final D d) { + return new F>>() { + public F> f(final E e) { + return new F>() { + public F f(final F$ f$) { + return new F() { + public I f(final G g) { + return uncurryF8(f).f(a, b, c, d, e, f$, g, h); + } + }; + } + }; + } + }; + } + }; + } + }; + } + }; + } + }; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Hash.java --- /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 { + private final F f; + + private Hash(final F 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 Hash comap(final F g) { + return new Hash(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 Hash hash(final F f) { + return new Hash(f); + } + + /** + * A hash that uses {@link Object#hashCode()}. + * + * @return A hash that uses {@link Object#hashCode()}. + */ + public static Hash anyHash() { + return new Hash(new F() { + public Integer f(final A a) { + return a.hashCode(); + } + }); + } + + /** + * A hash instance for the boolean type. + */ + public static final Hash booleanHash = anyHash(); + + /** + * A hash instance for the byte type. + */ + public static final Hash byteHash = anyHash(); + + /** + * A hash instance for the char type. + */ + public static final Hash charHash = anyHash(); + + /** + * A hash instance for the double type. + */ + public static final Hash doubleHash = anyHash(); + + /** + * A hash instance for the float type. + */ + public static final Hash floatHash = anyHash(); + + /** + * A hash instance for the int type. + */ + public static final Hash intHash = anyHash(); + + /** + * A hash instance for the long type. + */ + public static final Hash longHash = anyHash(); + + /** + * A hash instance for the short type. + */ + public static final Hash shortHash = anyHash(); + + /** + * A hash instance for the String type. + */ + public static final Hash stringHash = anyHash(); + + /** + * A hash instance for the {@link StringBuffer} type. + */ + public static final Hash stringBufferHash = new Hash(new F() { + 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 stringBuilderHash = new Hash(new F() { + 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 Either. + * @param hb Hash the right side of Either. + * @return A hash instance for the {@link Either} type. + */ + public static Hash> eitherHash(final Hash ha, final Hash hb) { + return new Hash>(new F, Integer>() { + public Integer f(final Either 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 Validation. + * @param hb Hash the succeeding side of Validation. + * @return A hash instance for the {@link Validation} type. + */ + public static Hash> validationHash(final Hash ha, final Hash hb) { + return eitherHash(ha, hb).comap(Validation.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 Hash> listHash(final Hash ha) { + return new Hash>(new F, Integer>() { + public Integer f(final List as) { + final int p = 419; + int r = 239; + List 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 Hash> nonEmptyListHash(final Hash ha) { + return listHash(ha).comap(NonEmptyList.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 Hash> optionHash(final Hash ha) { + return new Hash>(new F, Integer>() { + public Integer f(final Option 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 Hash> streamHash(final Hash ha) { + return new Hash>(new F, Integer>() { + public Integer f(final Stream as) { + final int p = 419; + int r = 239; + Stream 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 Hash> arrayHash(final Hash ha) { + return new Hash>(new F, Integer>() { + public Integer f(final Array 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 Hash> treeHash(final Hash ha) { + return streamHash(ha).comap(Tree.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 Hash> p1Hash(final Hash ha) { + return ha.comap(P1.__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 Hash> p2Hash(final Hash ha, final Hash hb) { + return new Hash>(new F, Integer>() { + public Integer f(final P2 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 Hash> p3Hash(final Hash ha, final Hash hb, final Hash hc) { + return new Hash>(new F, Integer>() { + public Integer f(final P3 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 Hash> p4Hash(final Hash ha, final Hash hb, final Hash hc, + final Hash hd) { + return new Hash>(new F, Integer>() { + public Integer f(final P4 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 Hash> p5Hash(final Hash ha, final Hash hb, final Hash hc, + final Hash hd, final Hash he) { + return new Hash>(new F, Integer>() { + public Integer f(final P5 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 Hash> p6Hash(final Hash ha, final Hash hb, + final Hash hc, final Hash hd, + final Hash he, final Hash hf) { + return new Hash>(new F, Integer>() { + public Integer f(final P6 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 Hash> p7Hash(final Hash ha, final Hash hb, + final Hash hc, final Hash hd, + final Hash he, final Hash hf, + final Hash hg) { + return new Hash>(new F, Integer>() { + public Integer f(final P7 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 Hash> p8Hash(final Hash ha, final Hash hb, + final Hash hc, final Hash hd, + final Hash he, final Hash hf, + final Hash hg, final Hash hh) { + return new Hash>(new F, Integer>() { + public Integer f(final P8 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 Hash> v2Hash(final Hash ea) { + return streamHash(ea).comap(V2.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 Hash> v3Hash(final Hash ea) { + return streamHash(ea).comap(V3.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 Hash> v4Hash(final Hash ea) { + return streamHash(ea).comap(V4.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 Hash> v5Hash(final Hash ea) { + return streamHash(ea).comap(V5.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 Hash> v6Hash(final Hash ea) { + return streamHash(ea).comap(V6.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 Hash> v7Hash(final Hash ea) { + return streamHash(ea).comap(V7.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 Hash> v8Hash(final Hash ea) { + return streamHash(ea).comap(V8.toStream_()); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/LcgRng.java --- /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 nextInt() { + P2 p = nextLong(); + int i = (int) p._2().longValue(); + return P.p(p._1(), i); + } + + + public P2 nextLong() { + P2 p = nextLong(seed); + return P.p(new LcgRng(p._1()), p._2()); + } + + /** + * + * @param seed + * @return Product of Seed and value + */ + static P2 nextLong(long seed) { + long newSeed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFFL; + long n = (Long) (newSeed >>> 16); + return P.p(newSeed, n); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Monoid.java --- /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: + *
    + *
  • Left Identity; forall x. sum(zero(), x) == x
  • + *
  • Right Identity; forall x. sum(x, zero()) == x
  • + *
  • Associativity; forall x. forall y. forall z. sum(sum(x, y), z) == sum(x, sum(y, z))
  • + *
+ * + * @version %build.number% + */ +public final class Monoid
{ + private final F> sum; + private final A zero; + + private Monoid(final F> 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 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 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> 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 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 as) { + return as.foldRight(new F2, A>() { + public A f(final A a, final P1 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 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 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, A> sumLeft() { + return new F, A>() { + public A f(final List 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, A> sumRight() { + return new F, A>() { + public A f(final List 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, A> sumLeftS() { + return new F, A>() { + public A f(final Stream 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 as, final A a) { + final Stream 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 Monoid monoid(final F> sum, final A zero) { + return new Monoid(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 Monoid monoid(final F2 sum, final A zero) { + return new Monoid(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 Monoid monoid(final Semigroup s, final A zero) { + return new Monoid(s.sum(), zero); + } + + /** + * A monoid that adds integers. + */ + public static final Monoid intAdditionMonoid = monoid(Semigroup.intAdditionSemigroup, 0); + + /** + * A monoid that multiplies integers. + */ + public static final Monoid intMultiplicationMonoid = monoid(Semigroup.intMultiplicationSemigroup, 1); + + /** + * A monoid that adds doubles. + */ + public static final Monoid doubleAdditionMonoid = monoid(Semigroup.doubleAdditionSemigroup, 0.0); + + /** + * A monoid that multiplies doubles. + */ + public static final Monoid doubleMultiplicationMonoid = monoid(Semigroup.doubleMultiplicationSemigroup, 1.0); + + /** + * A monoid that adds big integers. + */ + public static final Monoid bigintAdditionMonoid = monoid(Semigroup.bigintAdditionSemigroup, BigInteger.ZERO); + + /** + * A monoid that multiplies big integers. + */ + public static final Monoid bigintMultiplicationMonoid = + monoid(Semigroup.bigintMultiplicationSemigroup, BigInteger.ONE); + + /** + * A monoid that adds big decimals. + */ + public static final Monoid bigdecimalAdditionMonoid = + monoid(Semigroup.bigdecimalAdditionSemigroup, BigDecimal.ZERO); + + /** + * A monoid that multiplies big decimals. + */ + public static final Monoid bigdecimalMultiplicationMonoid = + monoid(Semigroup.bigdecimalMultiplicationSemigroup, BigDecimal.ONE); + + /** + * A monoid that adds natural numbers. + */ + public static final Monoid naturalAdditionMonoid = + monoid(Semigroup.naturalAdditionSemigroup, Natural.ZERO); + + /** + * A monoid that multiplies natural numbers. + */ + public static final Monoid naturalMultiplicationMonoid = + monoid(Semigroup.naturalMultiplicationSemigroup, Natural.ONE); + + /** + * A monoid that adds longs. + */ + public static final Monoid longAdditionMonoid = monoid(Semigroup.longAdditionSemigroup, 0L); + + /** + * A monoid that multiplies longs. + */ + public static final Monoid longMultiplicationMonoid = monoid(Semigroup.longMultiplicationSemigroup, 1L); + + /** + * A monoid that ORs booleans. + */ + public static final Monoid disjunctionMonoid = monoid(Semigroup.disjunctionSemigroup, false); + + /** + * A monoid that XORs booleans. + */ + public static final Monoid exclusiveDisjunctionMonoid = monoid(Semigroup.exclusiveDisjunctionSemiGroup, false); + + /** + * A monoid that ANDs booleans. + */ + public static final Monoid conjunctionMonoid = monoid(Semigroup.conjunctionSemigroup, true); + + /** + * A monoid that appends strings. + */ + public static final Monoid stringMonoid = monoid(Semigroup.stringSemigroup, ""); + + /** + * A monoid that appends string buffers. + */ + public static final Monoid stringBufferMonoid = monoid(Semigroup.stringBufferSemigroup, new StringBuffer()); + + /** + * A monoid that appends string builders. + */ + public static final Monoid 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 Monoid> functionMonoid(final Monoid mb) { + return monoid(Semigroup.functionSemigroup(mb.semigroup()), Function.constant(mb.zero)); + } + + /** + * A monoid for lists. + * + * @return A monoid for lists. + */ + public static Monoid> listMonoid() { + return monoid(Semigroup.listSemigroup(), List.nil()); + } + + /** + * A monoid for options. + * + * @return A monoid for options. + */ + public static Monoid> optionMonoid() { + return monoid(Semigroup.optionSemigroup(), Option.none()); + } + + /** + * A monoid for options that take the first available value. + * + * @return A monoid for options that take the first available value. + */ + public static Monoid> firstOptionMonoid() { + return monoid(Semigroup.firstOptionSemigroup(), Option.none()); + } + + /** + * A monoid for options that take the last available value. + * + * @return A monoid for options that take the last available value. + */ + public static Monoid> lastOptionMonoid() { + return monoid(Semigroup.lastOptionSemigroup(), Option.none()); + } + + /** + * A monoid for streams. + * + * @return A monoid for streams. + */ + public static Monoid> streamMonoid() { + return monoid(Semigroup.streamSemigroup(), Stream.nil()); + } + + /** + * A monoid for arrays. + * + * @return A monoid for arrays. + */ + @SuppressWarnings({"unchecked"}) + public static Monoid> arrayMonoid() { + return monoid(Semigroup.arraySemigroup(), Array.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 Monoid> setMonoid(final Ord o) { + return monoid(Semigroup.setSemigroup(), Set.empty(o)); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Ord.java --- /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 { + private final F> f; + + private Ord(final F> f) { + this.f = f; + } + + /** + * First-class ordering. + * + * @return A function that returns an ordering for its arguments. + */ + public F> 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 true if the given arguments are equal, false otherwise. + * + * @param a1 An instance to compare for equality to another. + * @param a2 An instance to compare for equality to another. + * @return true if the given arguments are equal, false otherwise. + */ + public boolean eq(final A a1, final A a2) { + return compare(a1, a2) == Ordering.EQ; + } + + /** + * Returns an Equal for this order. + * + * @return An Equal for this order. + */ + public Equal equal() { + return Equal.equal(curry(new F2() { + 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 Ord comap(final F f) { + return ord(F1Functions.o(F1Functions.o(F1Functions.andThen(f), this.f), f)); + } + + /** + * Returns true if the first given argument is less than the second given argument, + * false otherwise. + * + * @param a1 An instance to compare for ordering to another. + * @param a2 An instance to compare for ordering to another. + * @return true if the first given argument is less than the second given argument, + * false otherwise. + */ + public boolean isLessThan(final A a1, final A a2) { + return compare(a1, a2) == Ordering.LT; + } + + /** + * Returns true if the first given argument is greater than the second given + * argument, false otherwise. + * + * @param a1 An instance to compare for ordering to another. + * @param a2 An instance to compare for ordering to another. + * @return true if the first given argument is greater than the second given + * argument, false 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 isLessThan(final A a) { + return new F() { + 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 isGreaterThan(final A a) { + return new F() { + 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> max = curry(new F2() { + 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> min = curry(new F2() { + 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 Ord ord(final F> f) { + return new Ord(f); + } + + /** + * An order instance for the boolean type. + */ + public static final Ord booleanOrd = new Ord( + new F>() { + public F f(final Boolean a1) { + return new F() { + 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 byte type. + */ + public static final Ord byteOrd = new Ord( + new F>() { + public F f(final Byte a1) { + return new F() { + 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 char type. + */ + public static final Ord charOrd = new Ord( + new F>() { + public F f(final Character a1) { + return new F() { + 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 double type. + */ + public static final Ord doubleOrd = new Ord( + new F>() { + public F f(final Double a1) { + return new F() { + 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 float type. + */ + public static final Ord floatOrd = new Ord( + new F>() { + public F f(final Float a1) { + return new F() { + 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 int type. + */ + public static final Ord intOrd = new Ord( + new F>() { + public F f(final Integer a1) { + return new F() { + 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 BigInteger type. + */ + public static final Ord bigintOrd = new Ord( + new F>() { + public F f(final BigInteger a1) { + return new F() { + 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 BigDecimal type. + */ + public static final Ord bigdecimalOrd = new Ord( + new F>() { + public F f(final BigDecimal a1) { + return new F() { + 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 long type. + */ + public static final Ord longOrd = new Ord( + new F>() { + public F f(final Long a1) { + return new F() { + 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 short type. + */ + public static final Ord shortOrd = new Ord( + new F>() { + public F f(final Short a1) { + return new F() { + 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 orderingOrd = new Ord(curry(new F2() { + 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 stringOrd = new Ord( + new F>() { + public F f(final String a1) { + return new F() { + 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 stringBufferOrd = + new Ord(new F>() { + public F f(final StringBuffer a1) { + return new F() { + 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 stringBuilderOrd = + new Ord(new F>() { + public F f(final StringBuilder a1) { + return new F() { + 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 Ord> optionOrd(final Ord oa) { + return new Ord>(new F, F, Ordering>>() { + public F, Ordering> f(final Option o1) { + return new F, Ordering>() { + public Ordering f(final Option 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 Ord> eitherOrd(final Ord oa, final Ord ob) { + return new Ord>(new F, F, Ordering>>() { + public F, Ordering> f(final Either e1) { + return new F, Ordering>() { + public Ordering f(final Either 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 Ord> validationOrd(final Ord oa, final Ord ob) { + return eitherOrd(oa, ob).comap(Validation.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 Ord> listOrd(final Ord oa) { + return new Ord>(new F, F, Ordering>>() { + public F, Ordering> f(final List l1) { + return new F, Ordering>() { + public Ordering f(final List 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 Ord> nonEmptyListOrd(final Ord oa) { + return listOrd(oa).comap(NonEmptyList.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 Ord> streamOrd(final Ord oa) { + return new Ord>(new F, F, Ordering>>() { + public F, Ordering> f(final Stream s1) { + return new F, Ordering>() { + public Ordering f(final Stream 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 Ord> arrayOrd(final Ord oa) { + return new Ord>(new F, F, Ordering>>() { + public F, Ordering> f(final Array a1) { + return new F, Ordering>() { + public Ordering f(final Array 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 Ord> setOrd(final Ord oa) { + return streamOrd(oa).comap(new F, Stream>() { + public Stream f(final Set as) { + return as.toStream(); + } + }); + } + + /** + * An order instance for the {@link Unit} type. + */ + public static final Ord unitOrd = ord(curry(new F2() { + 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 Ord> p1Ord(final Ord oa) { + return oa.comap(P1.__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 Ord> p2Ord(final Ord oa, final Ord ob) { + return ord(curry(new F2, P2, Ordering>() { + public Ordering f(final P2 a, final P2 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 Ord> p3Ord(final Ord oa, final Ord ob, final Ord oc) { + return ord(curry(new F2, P3, Ordering>() { + public Ordering f(final P3 a, final P3 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 Natural type. + */ + public static final Ord naturalOrd = bigintOrd.comap(Natural.bigIntegerValue); + + + /** + * An order instance for the Comparable interface. + * + * @return An order instance for the Comparable interface. + */ + public static > Ord comparableOrd() { + return ord(new F>() { + public F f(final A a1) { + return new F() { + 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 Ord hashOrd() { + return Ord. ord(new F>() { + @Override + public F f(final A a) { + return new F() { + @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 Ord hashEqualsOrd() { + return Ord. ord(new F>() { + @Override + public F f(final A a) { + return new F() { + @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; + } + }; + } + }); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Ordering.java --- /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; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/P.java --- /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 F> p1() { + return new F>() { + public P1 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 P1 p(final A a) { + return new P1() { + public A _1() { + return a; + } + }; + } + + + public static P1 lazy(final P1 pa) { + return pa; + } + + public static P2 lazy(final P1 pa, final P1 pb) { + return new P2() { + @Override + public A _1() { + return pa._1(); + } + @Override + public B _2() { + return pb._1(); + } + }; + } + + public static P3 lazy(final P1 pa, final P1 pb, final P1 pc) { + return new P3() { + @Override + public A _1() { + return pa._1(); + } + @Override + public B _2() { + return pb._1(); + } + @Override + public C _3() { + return pc._1(); + } + }; + } + + public static P4 lazy(final P1 pa, final P1 pb, final P1 pc, final P1 pd) { + return new P4() { + @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 P5 lazy(final P1 pa, final P1 pb, final P1 pc, final P1 pd, P1 pe) { + return new P5() { + @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 P6 lazy(final P1 pa, final P1 pb, final P1 pc, final P1 pd, P1 pe, P1 pf) { + return new P6() { + @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 P7 lazy(final P1 pa, final P1 pb, final P1 pc, final P1 pd, P1 pe, P1 pf, P1 pg) { + return new P7() { + @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 P8 lazy(final P1 pa, final P1 pb, final P1 pc, final P1 pd, P1 pe, P1 pf, P1 pg, P1 ph) { + return new P8() { + @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 F>> p2() { + return new F>>() { + public F> f(final A a) { + return new F>() { + public P2 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 P2 p(final A a, final B b) { + return new P2() { + 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 F>>> p3() { + return new F>>>() { + public F>> f(final A a) { + return new F>>() { + public F> f(final B b) { + return new F>() { + public P3 f(final C c) { + return p(a, b, c); + } + }; + } + }; + } + }; + } + + /** + * 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 P3 p(final A a, final B b, final C c) { + return new P3() { + 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 F>>>> p4() { + return new F>>>>() { + public F>>> f(final A a) { + return new F>>>() { + public F>> f(final B b) { + return new F>>() { + public F> f(final C c) { + return new F>() { + public P4 f(final D d) { + return p(a, b, c, d); + } + }; + } + }; + } + }; + } + }; + } + + /** + * 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 P4 p(final A a, final B b, final C c, final D d) { + return new P4() { + 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 F>>>>> p5() { + return new F>>>>>() { + public F>>>> f(final A a) { + return new F>>>>() { + public F>>> f(final B b) { + return new F>>>() { + public F>> f(final C c) { + return new F>>() { + public F> f(final D d) { + return new F>() { + public P5 f(final E e) { + return p(a, b, c, d, e); + } + }; + } + }; + } + }; + } + }; + } + }; + } + + /** + * 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 P5 p(final A a, final B b, final C c, final D d, final E e) { + return new P5() { + 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 F>>>>>> p6() { + return new F>>>>>>() { + public F>>>>> f(final A a) { + return new F>>>>>() { + public F>>>> f(final B b) { + return new F>>>>() { + public F>>> f(final C c) { + return new F>>>() { + public F>> f(final D d) { + return new F>>() { + public F> f(final E e) { + return new F>() { + public P6 f(final F$ f) { + return p(a, b, c, d, e, f); + } + }; + } + }; + } + }; + } + }; + } + }; + } + }; + } + + /** + * 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 P6 p(final A a, final B b, final C c, final D d, final E e, final F$ f) { + return new P6() { + 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 F>>>>>>> p7() { + return new F>>>>>>>() { + public F>>>>>> f(final A a) { + return new F>>>>>>() { + public F>>>>> f(final B b) { + return new F>>>>>() { + public F>>>> f(final C c) { + return new F>>>>() { + public F>>> f(final D d) { + return new F>>>() { + public F>> f(final E e) { + return new F>>() { + public F> f(final F$ f) { + return new F>() { + public P7 f(final G g) { + return p(a, b, c, d, e, f, g); + } + }; + } + }; + } + }; + } + }; + } + }; + } + }; + } + }; + } + + /** + * 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 P7 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() { + 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 F>>>>>>>> p8() { + return new F>>>>>>>>() { + public F>>>>>>> f(final A a) { + return new F>>>>>>>() { + public F>>>>>> f(final B b) { + return new F>>>>>>() { + public F>>>>> f(final C c) { + return new F>>>>>() { + public F>>>> f(final D d) { + return new F>>>>() { + public F>>> f(final E e) { + return new F>>>() { + public F>> f(final F$ f) { + return new F>>() { + public F> f(final G g) { + return new F>() { + public P8 f(final H h) { + return p(a, b, c, d, e, f, g, h); + } + }; + } + }; + } + }; + } + }; + } + }; + } + }; + } + }; + } + }; + } + + /** + * 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 P8 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() { + 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 P1 lazy(F f) { + return new P1() { + @Override + public A _1() { + return f.f(unit()); + } + }; + } + + public static P2 lazy(F fa, F fb) { + return new P2() { + @Override + public A _1() { + return fa.f(unit()); + } + @Override + public B _2() { + return fb.f(unit()); + } + }; + } + + public static P3 lazy(F fa, F fb, F fc) { + return new P3() { + @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 P4 lazy(F fa, F fb, F fc, F fd) { + return new P4() { + @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 P5 lazy(F fa, F fb, F fc, F fd, F fe) { + return new P5() { + @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 P6 lazy(F fa, F fb, F fc, F fd, F fe, F ff) { + return new P6() { + @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 P7 lazy(F fa, F fb, F fc, F fd, F fe, F ff, F fg) { + return new P7() { + @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 P8 lazy(F fa, F fb, F fc, F fd, F fe, F ff, F fg, F fh) { + return new P8() { + @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()); + } + }; + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/P1.java --- /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 { + + /** + * 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 F, A> __1() { + return new F, A>() { + public A f(final P1 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 F, P1> fmap(final F f) { + return new F, P1>() { + public P1 f(final P1 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 P1 bind(final F> f) { + P1 self = this; + return new P1() { + 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 F> curry(final F f) { + return new F>() { + public P1 f(final A a) { + return new P1() { + 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 P1 apply(final P1> cf) { + P1 self = this; + return cf.bind(new F, P1>() { + public P1 f(final F 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 P1 bind(final P1 cb, final F> 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 P1 join(final P1> a) { + return a.bind(Function.>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 F, F, P1>> liftM2(final F> f) { + return Function.curry(new F2, P1, P1>() { + public P1 f(final P1 pa, final P1 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 P1> sequence(final List> as) { + return as.foldRight(liftM2(List.cons()), P.p(List.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 F>, P1>> sequenceList() { + return new F>, P1>>() { + public P1> f(final List> 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 P1> sequence(final Stream> as) { + return as.foldRight(liftM2(Stream.cons()), P.p(Stream.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 P1> sequence(final Array> as) { + return new P1>() { + public Array _1() { + return as.map(P1.__1()); + } + }; + } + + /** + * Map the element of the product. + * + * @param f The function to map with. + * @return A product with the given function applied. + */ + public P1 map(final F f) { + final P1 self = this; + return new P1() { + 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 memo() { + final P1 self = this; + return new P1() { + private final Object latch = new Object(); + @SuppressWarnings({"InstanceVariableMayNotBeInitialized"}) + private volatile SoftReference 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); + } + return a; + } + }; + } + + static P1 memo(F 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 F constant() { + + return new F() { + public A f(final B b) { + return P1.this._1(); + } + }; + } + + public String toString() { + return Show.p1Show(Show.anyShow()).showS(this); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/P2.java --- /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 { + /** + * 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 swap() { + return new P2() { + 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 P2 map1(final F f) { + return new P2() { + 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 P2 map2(final F f) { + return new P2() { + 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 P2 split(final F f, final F g) { + final F, P2> ff = map1_(f); + final F, P2> 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 P2 cobind(final F, C> k) { + return new P2() { + + 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, B> duplicate() { + final F, P2> 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 P2 inject(final C c) { + final F, 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 List sequenceW(final List, C>> fs) { + List.Buffer cs = List.Buffer.empty(); + for (final F, 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 Stream sequenceW(final Stream, C>> fs) { + return fs.isEmpty() + ? Stream.nil() + : Stream.cons(fs.head().f(this), new P1>() { + public Stream _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 _1_() { + return F1Functions.lazy(P2.__1()).f(this); + } + + /** + * Returns the 1-product projection over the second element. + * + * @return the 1-product projection over the second element. + */ + public final P1 _2_() { + return F1Functions.lazy(P2.__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 memo() { + P2 self = this; + return new P2() { + private final P1 a = P1.memo(u -> self._1()); + private final P1 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 F, P2> split_(final F f, final F g) { + return new F, P2>() { + public P2 f(final P2 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 F, P2> map1_(final F f) { + return new F, P2>() { + public P2 f(final P2 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 F, P2> map2_(final F f) { + return new F, P2>() { + public P2 f(final P2 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 P2 fanout(final F f, final F g, final B b) { + return join(P.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 P2 map(final F f, final P2 p) { + return p.split(f, f); + } + + /** + * Returns a curried form of {@link #swap()}. + * + * @return A curried form of {@link #swap()}. + */ + public static F, P2> swap_() { + return new F, P2>() { + public P2 f(final P2 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 F, A> __1() { + return new F, A>() { + public A f(final P2 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 F, B> __2() { + return new F, B>() { + public B f(final P2 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 F, C> tuple(final F> f) { + return new F, C>() { + public C f(final P2 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 F, C> tuple(final F2 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 F2 untuple(final F, C> f) { + return new F2() { + public C f(final A a, final B b) { + return f.f(P.p(a, b)); + } + }; + } + + public String toString() { + return Show.p2Show(Show.anyShow(), Show.anyShow()).showS(this); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/P3.java --- /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 { + /** + * 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 P3 map1(final F f) { + return new P3() { + 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 P3 map2(final F f) { + return new P3() { + 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 P3 map3(final F f) { + return new P3() { + 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 _1_() { + return F1Functions.lazy(P3.__1()).f(this); + } + + /** + * Returns the 1-product projection over the second element. + * + * @return the 1-product projection over the second element. + */ + public final P1 _2_() { + return F1Functions.lazy(P3.__2()).f(this); + } + + /** + * Returns the 1-product projection over the third element. + * + * @return the 1-product projection over the third element. + */ + public final P1 _3_() { + return F1Functions.lazy(P3.__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 memo() { + P3 self = this; + return new P3() { + private final P1 a = P1.memo(u -> self._1()); + private final P1 b = P1.memo(u -> self._2()); + private final P1 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 F, A> __1() { + return new F, A>() { + public A f(final P3 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 F, B> __2() { + return new F, B>() { + public B f(final P3 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 F, C> __3() { + return new F, C>() { + public C f(final P3 p) { + return p._3(); + } + }; + } + + public String toString() { + return Show.p3Show(Show.anyShow(), Show.anyShow(), Show.anyShow()).showS(this); + } + + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/P4.java --- /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 { + /** + * 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 P4 map1(final F f) { + return new P4() { + 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 P4 map2(final F f) { + return new P4() { + 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 P4 map3(final F f) { + return new P4() { + 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 P4 map4(final F f) { + return new P4() { + 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 _1_() { + return F1Functions.lazy(P4.__1()).f(this); + } + + /** + * Returns the 1-product projection over the second element. + * + * @return the 1-product projection over the second element. + */ + public final P1 _2_() { + return F1Functions.lazy(P4.__2()).f(this); + } + + /** + * Returns the 1-product projection over the third element. + * + * @return the 1-product projection over the third element. + */ + public final P1 _3_() { + return F1Functions.lazy(P4.__3()).f(this); + } + + /** + * Returns the 1-product projection over the fourth element. + * + * @return the 1-product projection over the fourth element. + */ + public final P1 _4_() { + return F1Functions.lazy(P4.__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 memo() { + P4 self = this; + return new P4() { + private final P1 a = P1.memo(u -> self._1()); + private final P1 b = P1.memo(u -> self._2()); + private final P1 c = P1.memo(u -> self._3()); + private final P1 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 F, A> __1() { + return new F, A>() { + public A f(final P4 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 F, B> __2() { + return new F, B>() { + public B f(final P4 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 F, C> __3() { + return new F, C>() { + public C f(final P4 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 F, D> __4() { + return new F, D>() { + public D f(final P4 p) { + return p._4(); + } + }; + } + + public String toString() { + return Show.p4Show(Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow()).showS(this); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/P5.java --- /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 { + /** + * 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 P5 map1(final F f) { + return new P5() { + 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 P5 map2(final F f) { + return new P5() { + 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 P5 map3(final F f) { + return new P5() { + 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 P5 map4(final F f) { + return new P5() { + 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 P5 map5(final F f) { + return new P5() { + 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 _1_() { + return F1Functions.lazy(P5.__1()).f(this); + } + + /** + * Returns the 1-product projection over the second element. + * + * @return the 1-product projection over the second element. + */ + public final P1 _2_() { + return F1Functions.lazy(P5.__2()).f(this); + } + + /** + * Returns the 1-product projection over the third element. + * + * @return the 1-product projection over the third element. + */ + public final P1 _3_() { + return F1Functions.lazy(P5.__3()).f(this); + } + + /** + * Returns the 1-product projection over the fourth element. + * + * @return the 1-product projection over the fourth element. + */ + public final P1 _4_() { + return F1Functions.lazy(P5.__4()).f(this); + } + + /** + * Returns the 1-product projection over the fifth element. + * + * @return the 1-product projection over the fifth element. + */ + public final P1 _5_() { + return F1Functions.lazy(P5.__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 memo() { + P5 self = this; + return new P5() { + private final P1 a = P1.memo(u -> self._1()); + private final P1 b = P1.memo(u -> self._2()); + private final P1 c = P1.memo(u -> self._3()); + private final P1 d = P1.memo(u -> self._4()); + private final P1 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 F, A> __1() { + return new F, A>() { + public A f(final P5 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 F, B> __2() { + return new F, B>() { + public B f(final P5 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 F, C> __3() { + return new F, C>() { + public C f(final P5 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 F, D> __4() { + return new F, D>() { + public D f(final P5 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 F, E> __5() { + return new F, E>() { + public E f(final P5 p) { + return p._5(); + } + }; + } + + public String toString() { + return Show.p5Show(Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow()).showS(this); + } + + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/P6.java --- /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 { + /** + * 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 P6 map1(final fj.F f) { + return new P6() { + 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 P6 map2(final fj.F f) { + return new P6() { + 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 P6 map3(final fj.F f) { + return new P6() { + 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 P6 map4(final fj.F f) { + return new P6() { + 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 P6 map5(final fj.F f) { + return new P6() { + 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 P6 map6(final fj.F f) { + return new P6() { + 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 _1_() { + return F1Functions.lazy(P6.__1()).f(this); + } + + /** + * Returns the 1-product projection over the second element. + * + * @return the 1-product projection over the second element. + */ + public final P1 _2_() { + return F1Functions.lazy(P6.__2()).f(this); + } + + /** + * Returns the 1-product projection over the third element. + * + * @return the 1-product projection over the third element. + */ + public final P1 _3_() { + return F1Functions.lazy(P6.__3()).f(this); + } + + /** + * Returns the 1-product projection over the fourth element. + * + * @return the 1-product projection over the fourth element. + */ + public final P1 _4_() { + return F1Functions.lazy(P6.__4()).f(this); + } + + /** + * Returns the 1-product projection over the fifth element. + * + * @return the 1-product projection over the fifth element. + */ + public final P1 _5_() { + return F1Functions.lazy(P6.__5()).f(this); + } + + /** + * Returns the 1-product projection over the sixth element. + * + * @return the 1-product projection over the sixth element. + */ + public final P1 _6_() { + return F1Functions.lazy(P6.__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 memo() { + P6 self = this; + return new P6() { + private final P1 a = P1.memo(u -> self._1()); + private final P1 b = P1.memo(u -> self._2()); + private final P1 c = P1.memo(u -> self._3()); + private final P1 d = P1.memo(u -> self._4()); + private final P1 e = P1.memo(u -> self._5()); + private final P1 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 fj.F, A> __1() { + return new fj.F, A>() { + public A f(final P6 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 fj.F, B> __2() { + return new fj.F, B>() { + public B f(final P6 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 fj.F, C> __3() { + return new fj.F, C>() { + public C f(final P6 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 fj.F, D> __4() { + return new fj.F, D>() { + public D f(final P6 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 fj.F, E> __5() { + return new fj.F, E>() { + public E f(final P6 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 fj.F, F$> __6() { + return new fj.F, F$>() { + public F$ f(final P6 p) { + return p._6(); + } + }; + } + + public String toString() { + return Show.p6Show(Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow()).showS(this); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/P7.java --- /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 { + /** + * 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 P7 map1(final fj.F f) { + return new P7() { + 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 P7 map2(final fj.F f) { + return new P7() { + 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 P7 map3(final fj.F f) { + return new P7() { + 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 P7 map4(final fj.F f) { + return new P7() { + 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 P7 map5(final fj.F f) { + return new P7() { + 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 P7 map6(final fj.F f) { + return new P7() { + 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 P7 map7(final fj.F f) { + return new P7() { + 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 _1_() { + return F1Functions.lazy(P7.__1()).f(this); + } + + /** + * Returns the 1-product projection over the second element. + * + * @return the 1-product projection over the second element. + */ + public final P1 _2_() { + return F1Functions.lazy(P7.__2()).f(this); + } + + /** + * Returns the 1-product projection over the third element. + * + * @return the 1-product projection over the third element. + */ + public final P1 _3_() { + return F1Functions.lazy(P7.__3()).f(this); + } + + /** + * Returns the 1-product projection over the fourth element. + * + * @return the 1-product projection over the fourth element. + */ + public final P1 _4_() { + return F1Functions.lazy(P7.__4()).f(this); + } + + /** + * Returns the 1-product projection over the fifth element. + * + * @return the 1-product projection over the fifth element. + */ + public final P1 _5_() { + return F1Functions.lazy(P7.__5()).f(this); + } + + /** + * Returns the 1-product projection over the sixth element. + * + * @return the 1-product projection over the sixth element. + */ + public final P1 _6_() { + return F1Functions.lazy(P7.__6()).f(this); + } + + /** + * Returns the 1-product projection over the seventh element. + * + * @return the 1-product projection over the seventh element. + */ + public final P1 _7_() { + return F1Functions.lazy(P7.__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 memo() { + P7 self = this; + return new P7() { + private final P1 a = P1.memo(u -> self._1()); + private final P1 b = P1.memo(u -> self._2()); + private final P1 c = P1.memo(u -> self._3()); + private final P1 d = P1.memo(u -> self._4()); + private final P1 e = P1.memo(u -> self._5()); + private final P1 f = P1.memo(u -> self._6()); + private final P1 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 fj.F, A> __1() { + return new fj.F, A>() { + public A f(final P7 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 fj.F, B> __2() { + return new fj.F, B>() { + public B f(final P7 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 fj.F, C> __3() { + return new fj.F, C>() { + public C f(final P7 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 fj.F, D> __4() { + return new fj.F, D>() { + public D f(final P7 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 fj.F, E> __5() { + return new fj.F, E>() { + public E f(final P7 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 fj.F, F$> __6() { + return new fj.F, F$>() { + public F$ f(final P7 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 fj.F, G> __7() { + return new fj.F, G>() { + public G f(final P7 p) { + return p._7(); + } + }; + } + + public String toString() { + return Show.p7Show(Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow()).showS(this); + } + + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/P8.java --- /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 { + /** + * 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 P8 map1(final fj.F f) { + return new P8() { + 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 P8 map2(final fj.F f) { + return new P8() { + 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 P8 map3(final fj.F f) { + return new P8() { + 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 P8 map4(final fj.F f) { + return new P8() { + 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 P8 map5(final fj.F f) { + return new P8() { + 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 P8 map6(final fj.F f) { + return new P8() { + 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 P8 map7(final fj.F f) { + return new P8() { + 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 P8 map8(final fj.F f) { + return new P8() { + 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 _1_() { + return F1Functions.lazy(P8.__1()).f(this); + } + + /** + * Returns the 1-product projection over the second element. + * + * @return the 1-product projection over the second element. + */ + public final P1 _2_() { + return F1Functions.lazy(P8.__2()).f(this); + } + + /** + * Returns the 1-product projection over the third element. + * + * @return the 1-product projection over the third element. + */ + public final P1 _3_() { + return F1Functions.lazy(P8.__3()).f(this); + } + + /** + * Returns the 1-product projection over the fourth element. + * + * @return the 1-product projection over the fourth element. + */ + public final P1 _4_() { + return F1Functions.lazy(P8.__4()).f(this); + } + + /** + * Returns the 1-product projection over the fifth element. + * + * @return the 1-product projection over the fifth element. + */ + public final P1 _5_() { + return F1Functions.lazy(P8.__5()).f(this); + } + + /** + * Returns the 1-product projection over the sixth element. + * + * @return the 1-product projection over the sixth element. + */ + public final P1 _6_() { + return F1Functions.lazy(P8.__6()).f(this); + } + + /** + * Returns the 1-product projection over the seventh element. + * + * @return the 1-product projection over the seventh element. + */ + public final P1 _7_() { + return F1Functions.lazy(P8.__7()).f(this); + } + + /** + * Returns the 1-product projection over the eighth element. + * + * @return the 1-product projection over the eighth element. + */ + public final P1 _8_() { + return F1Functions.lazy(P8.__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 memo() { + P8 self = this; + return new P8() { + private final P1 a = P1.memo(u -> self._1()); + private final P1 b = P1.memo(u -> self._2()); + private final P1 c = P1.memo(u -> self._3()); + private final P1 d = P1.memo(u -> self._4()); + private final P1 e = P1.memo(u -> self._5()); + private final P1 f = P1.memo(u -> self._6()); + private final P1 g = P1.memo(u -> self._7()); + private final P1 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 fj.F, A> __1() { + return new fj.F, A>() { + public A f(final P8 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 fj.F, B> __2() { + return new fj.F, B>() { + public B f(final P8 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 fj.F, C> __3() { + return new fj.F, C>() { + public C f(final P8 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 fj.F, D> __4() { + return new fj.F, D>() { + public D f(final P8 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 fj.F, E> __5() { + return new fj.F, E>() { + public E f(final P8 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 fj.F, F$> __6() { + return new fj.F, F$>() { + public F$ f(final P8 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 fj.F, G> __7() { + return new fj.F, G>() { + public G f(final P8 p) { + return p._7(); + } + }; + } + + /** + * Returns a function that returns the eighth element of a product. + * + * @return A function that returns the eighth element of a product. + */ + public static fj.F, H> __8() { + return new fj.F, H>() { + public H f(final P8 p) { + return p._8(); + } + }; + } + + public String toString() { + return Show.p8Show(Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow(), Show.anyShow()).showS(this); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Primitive.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/Primitive.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,548 @@ +package fj; + +/** + * Functions that convert between Java primitive types. + * + * @version %build.number% + */ +public final class Primitive { + private Primitive() { + throw new UnsupportedOperationException(); + } + + // BEGIN Boolean -> + + /** + * A function that converts booleans to bytes. + */ + public static final F Boolean_Byte = new F() { + public Byte f(final Boolean b) { + return (byte) (b ? 1 : 0); + } + }; + + /** + * A function that converts booleans to characters. + */ + public static final F Boolean_Character = new F() { + public Character f(final Boolean b) { + return (char) (b ? 1 : 0); + } + }; + + /** + * A function that converts booleans to doubles. + */ + public static final F Boolean_Double = new F() { + public Double f(final Boolean b) { + return b ? 1D : 0D; + } + }; + + /** + * A function that converts booleans to floats. + */ + public static final F Boolean_Float = new F() { + public Float f(final Boolean b) { + return b ? 1F : 0F; + } + }; + + /** + * A function that converts booleans to integers. + */ + public static final F Boolean_Integer = new F() { + public Integer f(final Boolean b) { + return b ? 1 : 0; + } + }; + + /** + * A function that converts booleans to longs. + */ + public static final F Boolean_Long = new F() { + public Long f(final Boolean b) { + return b ? 1L : 0L; + } + }; + + /** + * A function that converts booleans to shorts. + */ + public static final F Boolean_Short = new F() { + public Short f(final Boolean b) { + return (short) (b ? 1 : 0); + } + }; + + // END Boolean -> + + // BEGIN Byte -> + + /** + * A function that converts bytes to booleans. + */ + public static final F Byte_Boolean = new F() { + public Boolean f(final Byte b) { + return b != 0; + } + }; + + /** + * A function that converts bytes to characters. + */ + public static final F Byte_Character = new F() { + public Character f(final Byte b) { + return (char) (byte) b; + } + }; + + /** + * A function that converts bytes to doubles. + */ + public static final F Byte_Double = new F() { + public Double f(final Byte b) { + return (double) b; + } + }; + + /** + * A function that converts bytes to floats. + */ + public static final F Byte_Float = new F() { + public Float f(final Byte b) { + return (float) b; + } + }; + + /** + * A function that converts bytes to integers. + */ + public static final F Byte_Integer = new F() { + public Integer f(final Byte b) { + return (int) b; + } + }; + + /** + * A function that converts bytes to longs. + */ + public static final F Byte_Long = new F() { + public Long f(final Byte b) { + return (long) b; + } + }; + + /** + * A function that converts bytes to shorts. + */ + public static final F Byte_Short = new F() { + public Short f(final Byte b) { + return (short) b; + } + }; + + // END Byte -> + + // BEGIN Character -> + + /** + * A function that converts characters to booleans. + */ + public static final F Character_Boolean = new F() { + public Boolean f(final Character c) { + return c != 0; + } + }; + + /** + * A function that converts characters to bytes. + */ + public static final F Character_Byte = new F() { + public Byte f(final Character c) { + return (byte) (char) c; + } + }; + + /** + * A function that converts characters to doubles. + */ + public static final F Character_Double = new F() { + public Double f(final Character c) { + return (double) (char) c; + } + }; + + /** + * A function that converts characters to floats. + */ + public static final F Character_Float = new F() { + public Float f(final Character c) { + return (float) (char) c; + } + }; + + /** + * A function that converts characters to integers. + */ + public static final F Character_Integer = new F() { + public Integer f(final Character c) { + return (int) (char) c; + } + }; + + /** + * A function that converts characters to longs. + */ + public static final F Character_Long = new F() { + public Long f(final Character c) { + return (long) (char) c; + } + }; + + /** + * A function that converts characters to shorts. + */ + public static final F Character_Short = new F() { + public Short f(final Character c) { + return (short) (char) c; + } + }; + + // END Character -> + + // BEGIN Double -> + + /** + * A function that converts doubles to booleans. + */ + public static final F Double_Boolean = new F() { + public Boolean f(final Double d) { + return d != 0D; + } + }; + + /** + * A function that converts doubles to bytes. + */ + public static final F Double_Byte = new F() { + public Byte f(final Double d) { + return (byte) (double) d; + } + }; + + /** + * A function that converts doubles to characters. + */ + public static final F Double_Character = new F() { + public Character f(final Double d) { + return (char) (double) d; + } + }; + + /** + * A function that converts doubles to floats. + */ + public static final F Double_Float = new F() { + public Float f(final Double d) { + return (float) (double) d; + } + }; + + /** + * A function that converts doubles to integers. + */ + public static final F Double_Integer = new F() { + public Integer f(final Double d) { + return (int) (double) d; + } + }; + + /** + * A function that converts doubles to longs. + */ + public static final F Double_Long = new F() { + public Long f(final Double d) { + return (long) (double) d; + } + }; + + /** + * A function that converts doubles to shorts. + */ + public static final F Double_Short = new F() { + public Short f(final Double d) { + return (short) (double) d; + } + }; + + // END Double -> + + // BEGIN Float -> + + /** + * A function that converts floats to booleans. + */ + public static final F Float_Boolean = new F() { + public Boolean f(final Float f) { + return f != 0F; + } + }; + + /** + * A function that converts floats to bytes. + */ + public static final F Float_Byte = new F() { + public Byte f(final Float f) { + return (byte) (float) f; + } + }; + + /** + * A function that converts floats to characters. + */ + public static final F Float_Character = new F() { + public Character f(final Float f) { + return (char) (float) f; + } + }; + + /** + * A function that converts floats to doubles. + */ + public static final F Float_Double = new F() { + public Double f(final Float f) { + return (double) (float) f; + } + }; + + /** + * A function that converts floats to integers. + */ + public static final F Float_Integer = new F() { + public Integer f(final Float f) { + return (int) (float) f; + } + }; + + /** + * A function that converts floats to longs. + */ + public static final F Float_Long = new F() { + public Long f(final Float f) { + return (long) (float) f; + } + }; + + /** + * A function that converts floats to shorts. + */ + public static final F Float_Short = new F() { + public Short f(final Float f) { + return (short) (float) f; + } + }; + + // END Float -> + + // BEGIN Integer -> + + /** + * A function that converts integers to booleans. + */ + public static final F Integer_Boolean = new F() { + public Boolean f(final Integer i) { + return i != 0; + } + }; + + /** + * A function that converts integers to bytes. + */ + public static final F Integer_Byte = new F() { + public Byte f(final Integer i) { + return (byte) (int) i; + } + }; + + /** + * A function that converts integers to characters. + */ + public static final F Integer_Character = new F() { + public Character f(final Integer i) { + return (char) (int) i; + } + }; + + /** + * A function that converts integers to doubles. + */ + public static final F Integer_Double = new F() { + public Double f(final Integer i) { + return (double) i; + } + }; + + /** + * A function that converts integers to floats. + */ + public static final F Integer_Float = new F() { + public Float f(final Integer i) { + return (float) i; + } + }; + + /** + * A function that converts integers to longs. + */ + public static final F Integer_Long = new F() { + public Long f(final Integer i) { + return (long) i; + } + }; + + /** + * A function that converts integers to shorts. + */ + public static final F Integer_Short = new F() { + public Short f(final Integer i) { + return (short) (int) i; + } + }; + + // END Integer -> + + // BEGIN Long -> + + /** + * A function that converts longs to booleans. + */ + public static final F Long_Boolean = new F() { + public Boolean f(final Long l) { + return l != 0L; + } + }; + + /** + * A function that converts longs to bytes. + */ + public static final F Long_Byte = new F() { + public Byte f(final Long l) { + return (byte) (long) l; + } + }; + + /** + * A function that converts longs to characters. + */ + public static final F Long_Character = new F() { + public Character f(final Long l) { + return (char) (long) l; + } + }; + + /** + * A function that converts longs to doubles. + */ + public static final F Long_Double = new F() { + public Double f(final Long l) { + return (double) (long) l; + } + }; + + /** + * A function that converts longs to floats. + */ + public static final F Long_Float = new F() { + public Float f(final Long l) { + return (float) (long) l; + } + }; + + /** + * A function that converts longs to integers. + */ + public static final F Long_Integer = new F() { + public Integer f(final Long l) { + return (int) (long) l; + } + }; + + /** + * A function that converts longs to shorts. + */ + public static final F Long_Short = new F() { + public Short f(final Long l) { + return (short) (long) l; + } + }; + + // END Long -> + + // BEGIN Short -> + + /** + * A function that converts shorts to booleans. + */ + public static final F Short_Boolean = new F() { + public Boolean f(final Short s) { + return s != 0; + } + }; + + /** + * A function that converts shorts to bytes. + */ + public static final F Short_Byte = new F() { + public Byte f(final Short s) { + return (byte) (short) s; + } + }; + + /** + * A function that converts shorts to characters. + */ + public static final F Short_Character = new F() { + public Character f(final Short s) { + return (char) (short) s; + } + }; + + /** + * A function that converts shorts to doubles. + */ + public static final F Short_Double = new F() { + public Double f(final Short s) { + return (double) (short) s; + } + }; + + /** + * A function that converts shorts to floats. + */ + public static final F Short_Float = new F() { + public Float f(final Short s) { + return (float) (short) s; + } + }; + + /** + * A function that converts shorts to integers. + */ + public static final F Short_Integer = new F() { + public Integer f(final Short s) { + return (int) (short) s; + } + }; + + /** + * A function that converts shorts to longs. + */ + public static final F Short_Long = new F() { + public Long f(final Short s) { + return (long) (short) s; + } + }; + + // END Short +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Rng.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/Rng.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,23 @@ +package fj; + +/** + * Created by MarkPerry on 7/07/2014. + */ +public abstract class Rng { + + public abstract P2 nextInt(); + + public abstract P2 nextLong(); + + // [low, high] inclusive + public P2 range(int low, int high) { + return nextNatural().map2(x -> (x % (high - low + 1)) + low); + } + + + public P2 nextNatural() { + return nextInt().map2(x -> x < 0 ? -(x + 1) : x); + } + + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Semigroup.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/Semigroup.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,472 @@ +package fj; + +import static fj.Function.curry; + +import fj.data.Array; +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 java.math.BigInteger; +import java.math.BigDecimal; + +/** + * Implementations must satisfy the law of associativity: + *
    + *
  • Associativity; forall x. forall y. forall z. sum(sum(x, y), z) == sum(x, sum(y, z))
  • + *
+ * + * @version %build.number% + */ +public final class Semigroup
{ + private final F> sum; + + private Semigroup(final F> sum) { + this.sum = 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 semigroup. + * + * @param a1 The value to sum. + * @return A function that sums the given value according to this semigroup. + */ + public F sum(final A a1) { + return sum.f(a1); + } + + /** + * Returns a function that sums according to this semigroup. + * + * @return A function that sums according to this semigroup. + */ + public F> sum() { + return sum; + } + + /** + * Constructs a semigroup from the given function. + * + * @param sum The function to construct this semigroup with. + * @return A semigroup from the given function. + */ + public static Semigroup semigroup(final F> sum) { + return new Semigroup(sum); + } + + /** + * Constructs a semigroup from the given function. + * + * @param sum The function to construct this semigroup with. + * @return A semigroup from the given function. + */ + public static Semigroup semigroup(final F2 sum) { + return new Semigroup(curry(sum)); + } + + /** + * A semigroup that adds integers. + */ + public static final Semigroup intAdditionSemigroup = semigroup(new F2() { + public Integer f(final Integer i1, final Integer i2) { + return i1 + i2; + } + }); + + /** + * A semigroup that adds doubles. + */ + public static final Semigroup doubleAdditionSemigroup = semigroup(new F2() { + public Double f(final Double d1, final Double d2) { + return d1 + d2; + } + }); + + /** + * A semigroup that multiplies integers. + */ + public static final Semigroup intMultiplicationSemigroup = semigroup(new F2() { + public Integer f(final Integer i1, final Integer i2) { + return i1 * i2; + } + }); + + /** + * A semigroup that multiplies doubles. + */ + public static final Semigroup doubleMultiplicationSemigroup = semigroup(new F2() { + public Double f(final Double d1, final Double d2) { + return d1 * d2; + } + }); + + /** + * A semigroup that yields the maximum of integers. + */ + public static final Semigroup intMaximumSemigroup = semigroup(Ord.intOrd.max); + + /** + * A semigroup that yields the minimum of integers. + */ + public static final Semigroup intMinimumSemigroup = semigroup(Ord.intOrd.min); + + /** + * A semigroup that adds big integers. + */ + public static final Semigroup bigintAdditionSemigroup = + semigroup(new F2() { + public BigInteger f(final BigInteger i1, final BigInteger i2) { + return i1.add(i2); + } + }); + + /** + * A semigroup that multiplies big integers. + */ + public static final Semigroup bigintMultiplicationSemigroup = + semigroup(new F2() { + public BigInteger f(final BigInteger i1, final BigInteger i2) { + return i1.multiply(i2); + } + }); + + /** + * A semigroup that yields the maximum of big integers. + */ + public static final Semigroup bigintMaximumSemigroup = semigroup(Ord.bigintOrd.max); + + /** + * A semigroup that yields the minimum of big integers. + */ + public static final Semigroup bigintMinimumSemigroup = semigroup(Ord.bigintOrd.min); + + /** + * A semigroup that adds big decimals. + */ + public static final Semigroup bigdecimalAdditionSemigroup = + semigroup(new F2() { + public BigDecimal f(final BigDecimal i1, final BigDecimal i2) { + return i1.add(i2); + } + }); + + /** + * A semigroup that multiplies big decimals. + */ + public static final Semigroup bigdecimalMultiplicationSemigroup = + semigroup(new F2() { + public BigDecimal f(final BigDecimal i1, final BigDecimal i2) { + return i1.multiply(i2); + } + }); + + /** + * A semigroup that yields the maximum of big decimals. + */ + public static final Semigroup bigDecimalMaximumSemigroup = semigroup(Ord.bigdecimalOrd.max); + + /** + * A semigroup that yields the minimum of big decimals. + */ + public static final Semigroup bigDecimalMinimumSemigroup = semigroup(Ord.bigdecimalOrd.min); + + /** + * A semigroup that multiplies natural numbers. + */ + public static final Semigroup naturalMultiplicationSemigroup = + semigroup(new F2() { + public Natural f(final Natural n1, final Natural n2) { + return n1.multiply(n2); + } + }); + + /** + * A semigroup that multiplies natural numbers. + */ + public static final Semigroup naturalAdditionSemigroup = + semigroup(new F2() { + public Natural f(final Natural n1, final Natural n2) { + return n1.add(n2); + } + }); + + /** + * A semigroup that yields the maximum of natural numbers. + */ + public static final Semigroup naturalMaximumSemigroup = semigroup(Ord.naturalOrd.max); + + /** + * A semigroup that yields the minimum of natural numbers. + */ + public static final Semigroup naturalMinimumSemigroup = semigroup(Ord.naturalOrd.min); + + /** + * A semigroup that adds longs. + */ + public static final Semigroup longAdditionSemigroup = semigroup(new F2() { + public Long f(final Long x, final Long y) { + return x + y; + } + }); + + /** + * A semigroup that multiplies longs. + */ + public static final Semigroup longMultiplicationSemigroup = semigroup(new F2() { + public Long f(final Long x, final Long y) { + return x * y; + } + }); + + /** + * A semigroup that yields the maximum of longs. + */ + public static final Semigroup longMaximumSemigroup = semigroup(Ord.longOrd.max); + + /** + * A semigroup that yields the minimum of longs. + */ + public static final Semigroup longMinimumSemigroup = semigroup(Ord.longOrd.min); + + /** + * A semigroup that ORs booleans. + */ + public static final Semigroup disjunctionSemigroup = semigroup(new F2() { + public Boolean f(final Boolean b1, final Boolean b2) { + return b1 || b2; + } + }); + + /** + * A semigroup that XORs booleans. + */ + public static final Semigroup exclusiveDisjunctionSemiGroup = semigroup(new F2() { + public Boolean f(final Boolean p, final Boolean q) { + return p && !q || !p && q; + } + }); + + /** + * A semigroup that ANDs booleans. + */ + public static final Semigroup conjunctionSemigroup = semigroup(new F2() { + public Boolean f(final Boolean b1, final Boolean b2) { + return b1 && b2; + } + }); + + /** + * A semigroup that appends strings. + */ + public static final Semigroup stringSemigroup = semigroup(new F2() { + public String f(final String s1, final String s2) { + return s1 + s2; + } + }); + + /** + * A semigroup that appends string buffers. + */ + public static final Semigroup stringBufferSemigroup = + semigroup(new F2() { + public StringBuffer f(final StringBuffer s1, final StringBuffer s2) { + return new StringBuffer(s1).append(s2); + } + }); + + /** + * A semigroup that appends string builders. + */ + public static final Semigroup stringBuilderSemigroup = + semigroup(new F2() { + public StringBuilder f(final StringBuilder s1, final StringBuilder s2) { + return new StringBuilder(s1).append(s2); + } + }); + + /** + * A semigroup for functions. + * + * @param sb The smeigroup for the codomain. + * @return A semigroup for functions. + */ + public static Semigroup> functionSemigroup(final Semigroup sb) { + return semigroup(new F2, F, F>() { + public F f(final F a1, final F a2) { + return new F() { + public B f(final A a) { + return sb.sum(a1.f(a), a2.f(a)); + } + }; + } + }); + } + + /** + * A semigroup for lists. + * + * @return A semigroup for lists. + */ + public static Semigroup> listSemigroup() { + return semigroup(new F2, List, List>() { + public List f(final List a1, final List a2) { + return a1.append(a2); + } + }); + } + + /** + * A semigroup for non-empty lists. + * + * @return A semigroup for non-empty lists. + */ + public static Semigroup> nonEmptyListSemigroup() { + return semigroup(new F2, NonEmptyList, NonEmptyList>() { + public NonEmptyList f(final NonEmptyList a1, final NonEmptyList a2) { + return a1.append(a2); + } + }); + } + + /** + * A semigroup for optional values. + ** @return A semigroup for optional values. + */ + public static Semigroup> optionSemigroup() { + return semigroup(new F2, Option, Option>() { + public Option f(final Option a1, final Option a2) { + return a1.isSome() ? a1 : a2; + } + }); + } + + /** + * A semigroup for optional values that take the first available value. + * + * @return A semigroup for optional values that take the first available value. + */ + public static Semigroup> firstOptionSemigroup() { + return semigroup(new F2, Option, Option>() { + public Option f(final Option a1, final Option a2) { + return a1.orElse(a2); + } + }); + } + + /** + * A semigroup for optional values that take the last available value. + * + * @return A semigroup for optional values that take the last available value. + */ + public static Semigroup> lastOptionSemigroup() { + return semigroup(new F2, Option, Option>() { + public Option f(final Option a1, final Option a2) { + return a2.orElse(a1); + } + }); + } + + /** + * A semigroup for streams. + * + * @return A semigroup for streams. + */ + public static Semigroup> streamSemigroup() { + return semigroup(new F2, Stream, Stream>() { + public Stream f(final Stream a1, final Stream a2) { + return a1.append(a2); + } + }); + } + + /** + * A semigroup for arrays. + * + * @return A semigroup for arrays. + */ + public static Semigroup> arraySemigroup() { + return semigroup(new F2, Array, Array>() { + public Array f(final Array a1, final Array a2) { + return a1.append(a2); + } + }); + } + + /** + * A semigroup for unary products. + * + * @param sa A semigroup for the product's type. + * @return A semigroup for unary products. + */ + public static Semigroup> p1Semigroup(final Semigroup sa) { + return semigroup(new F2, P1, P1>() { + public P1 f(final P1 a1, final P1 a2) { + return new P1() { + public A _1() { + return sa.sum(a1._1(), a2._1()); + } + }; + } + }); + } + + /** + * A semigroup for binary products. + * + * @param sa A semigroup for the product's first type. + * @param sb A semigroup for the product's second type. + * @return A semigroup for binary products. + */ + public static Semigroup> p2Semigroup(final Semigroup sa, final Semigroup sb) { + return semigroup(new F2, P2, P2>() { + public P2 f(final P2 a1, final P2 a2) { + return new P2() { + public A _1() { + return sa.sum(a1._1(), a2._1()); + } + + public B _2() { + return sb.sum(a1._2(), a2._2()); + } + }; + } + }); + } + + /** + * A semigroup for the Unit value. + */ + public static final Semigroup unitSemigroup = semigroup(new F2() { + public Unit f(final Unit u1, final Unit u2) { + return Unit.unit(); + } + }); + + /** + * A semigroup for sets. + * + * @return a semigroup for sets. + */ + public static Semigroup> setSemigroup() { + return semigroup(new F2, Set, Set>() { + public Set f(final Set a, final Set b) { + return a.union(b); + } + }); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Show.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/Show.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,676 @@ +package fj; + +import fj.data.Array; +import fj.data.Either; +import fj.data.LazyString; +import fj.data.List; +import fj.data.Natural; +import fj.data.NonEmptyList; +import fj.data.Option; +import fj.data.Stream; +import fj.data.Tree; +import fj.data.Validation; +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.BigDecimal; +import java.math.BigInteger; + +import static fj.Function.compose; +import static fj.P.p; +import static fj.Unit.unit; +import static fj.data.Stream.cons; +import static fj.data.Stream.fromString; +import static fj.data.Stream.join; +import static fj.data.Stream.nil; +import static fj.data.Stream.single; + +/** + * Renders an object for display. + * + * @version %build.number% + */ +public final class Show { + private final F> f; + + private Show(final F> f) { + this.f = f; + } + + /** + * Maps the given function across this show as a contra-variant functor. + * + * @param f The function to map. + * @return A new show. + */ + public Show comap(final F f) { + return show(compose(this.f, f)); + } + + /** + * Returns the display rendering of the given argument. + * + * @param a The argument to display. + * @return The display rendering of the given argument. + */ + public Stream show(final A a) { + return f.f(a); + } + + /** + * Returns the display rendering of the given argument. + * + * @param a The argument to display. + * @return The display rendering of the given argument. + */ + public List showl(final A a) { + return show(a).toList(); + } + + /** + * Returns the display rendering of the given argument as a String. + * + * @param a The argument to display. + * @return The display rendering of the given argument as a String. + */ + public String showS(final A a) { + return Stream.asString(show(a)); + } + + /** + * Returns the transformation equivalent to this show. + * + * @return the transformation equivalent to this show. + */ + public F showS_() { + return new F() { + public String f(final A a) { + return showS(a); + } + }; + } + + /** + * Returns the transformation equivalent to this show. + * + * @return the transformation equivalent to this show. + */ + public F> show_() { + return f; + } + + /** + * Prints the given argument to the standard output stream with a new line. + * + * @param a The argument to print. + * @return The unit value. + */ + public Unit println(final A a) { + print(a); + System.out.println(); + return unit(); + } + + /** + * Prints the given argument to the standard output stream. + * + * @param a The argument to print. + * @return The unit value. + */ + public Unit print(final A a) { + final char[] buffer = new char[8192]; + int c = 0; + for (Stream cs = show(a); cs.isNotEmpty(); cs = cs.tail()._1()) { + buffer[c] = cs.head(); + c++; + if (c == 8192) { + System.out.print(buffer); + c = 0; + } + } + System.out.print(Array.copyOfRange(buffer, 0, c)); + return unit(); + } + + /** + * Prints the given argument to the standard error stream with a new line. + * + * @param a The argument to print. + */ + public void printlnE(final A a) { + System.err.println(showS(a)); + } + + /** + * Returns a show instance using the given function. + * + * @param f The function to use for the returned show instance. + * @return A show instance. + */ + public static Show show(final F> f) { + return new Show(f); + } + + /** + * Returns a show instance using the given function. + * + * @param f The function to use for the returned show instance. + * @return A show instance. + */ + public static Show showS(final F f) { + return new Show(new F>() { + public Stream f(final A a) { + return fromString(f.f(a)); + } + }); + } + + /** + * Returns a show instance that uses {@link Object#toString()} to perform the display rendering. + * + * @return A show instance that uses {@link Object#toString()} to perform the display rendering. + */ + public static Show anyShow() { + return new Show(new F>() { + public Stream f(final A a) { + return Stream.fromString((a == null) ? "null" : a.toString()); + } + }); + } + + /** + * A show instance for the boolean type. + */ + public static final Show booleanShow = anyShow(); + + /** + * A show instance for the byte type. + */ + public static final Show byteShow = anyShow(); + + /** + * A show instance for the char type. + */ + public static final Show charShow = anyShow(); + + /** + * A show instance for the double type. + */ + public static final Show doubleShow = anyShow(); + + /** + * A show instance for the float type. + */ + public static final Show floatShow = anyShow(); + + /** + * A show instance for the int type. + */ + public static final Show intShow = anyShow(); + + /** + * A show instance for the BigInteger type. + */ + public static final Show bigintShow = anyShow(); + + /** + * A show instance for the BigDecimal type. + */ + public static final Show bigdecimalShow = anyShow(); + + /** + * A show instance for the long type. + */ + public static final Show longShow = anyShow(); + + /** + * A show instance for the short type. + */ + public static final Show shortShow = anyShow(); + + /** + * A show instance for the {@link String} type. + */ + public static final Show stringShow = anyShow(); + + /** + * A show instance for the {@link StringBuffer} type. + */ + public static final Show stringBufferShow = anyShow(); + + /** + * A show instance for the {@link StringBuilder} type. + */ + public static final Show stringBuilderShow = anyShow(); + + /** + * A show instance for the {@link Option} type. + * + * @param sa Show for the element of the option. + * @return A show instance for the {@link Option} type. + */ + public static Show> optionShow(final Show sa) { + return new Show>(new F, Stream>() { + public Stream f(final Option o) { + return o.isNone() ? + fromString("None") : + fromString("Some(").append(sa.f.f(o.some())).append(single(')')); + } + }); + } + + /** + * A show instance for the {@link Either} type. + * + * @param sa Show for the left side of the {@link Either}. + * @param sb Show for the right side of the {@link Either}. + * @return A show instance for the {@link Either} type. + */ + public static Show> eitherShow(final Show sa, final Show sb) { + return new Show>(new F, Stream>() { + public Stream f(final Either e) { + return e.isLeft() ? + fromString("Left(").append(sa.f.f(e.left().value())).append(single(')')) : + fromString("Right(").append(sb.f.f(e.right().value())).append(single(')')); + } + }); + } + + /** + * A show instance for the {@link Validation} type. + * + * @param sa Show for the fail side of the {@link Validation}. + * @param sb Show for the success side of the {@link Validation}. + * @return A show instance for the {@link Validation} type. + */ + public static Show> validationShow(final Show sa, final Show sb) { + return new Show>(new F, Stream>() { + public Stream f(final Validation v) { + return v.isFail() ? + fromString("Fail(").append(sa.f.f(v.fail())).append(single(')')) : + fromString("Success(").append(sb.f.f(v.success())).append(single(')')); + } + }); + } + + /** + * A show instance for the {@link Stream} type. + * + * @param sa Show for the elements of the Stream. + * @return A show instance for the {@link Stream} type. + */ + public static Show> listShow(final Show sa) { + return new Show>(new F, Stream>() { + public Stream f(final List as) { + return streamShow(sa).show(as.toStream()); + } + }); + } + + /** + * A show instance for the {@link NonEmptyList} type. + * + * @param sa Show for the elements of the non-empty Stream. + * @return A show instance for the {@link NonEmptyList} type. + */ + public static Show> nonEmptyListShow(final Show sa) { + return listShow(sa).comap(NonEmptyList.toList_()); + } + + /** + * A show instance for the {@link Tree} type. + * + * @param sa Show for the elements of the tree. + * @return A show instance for the {@link Tree} type. + */ + public static Show> treeShow(final Show sa) { + return new Show>(new F, Stream>() { + public Stream f(final Tree a) { + final Stream b = sa.f.f(a.root()) + .append(p1Show(streamShow(treeShow(sa))).f.f(a.subForest())) + .snoc(')'); + return cons('(', p(b)); + } + }); + } + + /** + * A show instance for the {@link Stream} type. + * + * @param sa Show for the elements of the stream. + * @return A show instance for the {@link Stream} type. + */ + public static Show> streamShow(final Show sa) { + return new Show>(new F, Stream>() { + public Stream f(final Stream as) { + return join(as.map(sa.show_()).intersperse(fromString(",")).cons(fromString("<")).snoc(p(fromString(">")))); + } + }); + } + + /** + * A show instance for the {@link Array} type. + * + * @param sa Show for the elements of the array. + * @return A show instance for the {@link Array} type. + */ + public static Show> arrayShow(final Show sa) { + return new Show>(new F, Stream>() { + public Stream f(final Array as) { + Stream b = nil(); + + for (int i = 0; i < as.length(); i++) { + b = b.append(sa.f.f(as.get(i))); + + if (i != as.length() - 1) + b = b.snoc(','); + } + + b = b.snoc('}'); + + return cons('{', p(b)); + } + }); + } + + /** + * A show instance for the {@link Class} type. + * + * @return A show instance for the {@link Class} type. + */ + public static Show> classShow() { + return new Show>(new F, Stream>() { + public Stream f(final Class c) { + return anyShow().show(c.clas()); + } + }); + } + + /** + * A show instance for the {@link P1 tuple-1} type. + * + * @param sa Show for the first element of the tuple. + * @return A show instance for the {@link P1 tuple-1} type. + */ + public static Show> p1Show(final Show sa) { + return new Show>(new F, Stream>() { + public Stream f(final P1 p) { + return cons('(', p(sa.show(p._1()))).snoc(')'); + } + }); + } + + /** + * A show instance for the {@link P2 tuple-2} type. + * + * @param sa Show for the first element of the tuple. + * @param sb Show for the second element of the tuple. + * @return A show instance for the {@link P2 tuple-2} type. + */ + public static Show> p2Show(final Show sa, final Show sb) { + return new Show>(new F, Stream>() { + public Stream f(final P2 p) { + return cons('(', p(sa.show(p._1()))).snoc(',').append(sb.show(p._2())).snoc(')'); + } + }); + } + + /** + * A show instance for the {@link P3 tuple-3} type. + * + * @param sa Show for the first element of the tuple. + * @param sb Show for the second element of the tuple. + * @param sc Show for the third element of the tuple. + * @return A show instance for the {@link P3 tuple-3} type. + */ + public static Show> p3Show(final Show sa, final Show sb, final Show sc) { + return new Show>(new F, Stream>() { + public Stream f(final P3 p) { + return cons('(', p(sa.show(p._1()))).snoc(',').append(sb.show(p._2())).snoc(',') + .append(sc.show(p._3())).snoc(')'); + } + }); + } + + /** + * A show instance for the {@link P4 tuple-4} type. + * + * @param sa Show for the first element of the tuple. + * @param sb Show for the second element of the tuple. + * @param sc Show for the third element of the tuple. + * @param sd Show for the fourth element of the tuple. + * @return A show instance for the {@link P4 tuple-4} type. + */ + public static Show> p4Show(final Show sa, final Show sb, + final Show sc, final Show sd) { + return new Show>(new F, Stream>() { + public Stream f(final P4 p) { + return cons('(', p(sa.show(p._1()))).snoc(',').append(sb.show(p._2())).snoc(',') + .append(sc.show(p._3())).snoc(',').append(sd.show(p._4())).snoc(')'); + } + }); + } + + /** + * A show instance for the {@link P5 tuple-5} type. + * + * @param sa Show for the first element of the tuple. + * @param sb Show for the second element of the tuple. + * @param sc Show for the third element of the tuple. + * @param sd Show for the fourth element of the tuple. + * @param se Show for the fifth element of the tuple. + * @return A show instance for the {@link P5 tuple-5} type. + */ + public static Show> p5Show(final Show sa, final Show sb, + final Show sc, final Show sd, final Show se) { + return new Show>(new F, Stream>() { + public Stream f(final P5 p) { + return cons('(', p(sa.show(p._1()))).snoc(',').append(sb.show(p._2())).snoc(',') + .append(sc.show(p._3())).snoc(',').append(sd.show(p._4())).snoc(',').append(se.show(p._5())).snoc(')'); + } + }); + } + + /** + * A show instance for the {@link P6 tuple-6} type. + * + * @param sa Show for the first element of the tuple. + * @param sb Show for the second element of the tuple. + * @param sc Show for the third element of the tuple. + * @param sd Show for the fourth element of the tuple. + * @param se Show for the fifth element of the tuple. + * @param sf Show for the sixth element of the tuple. + * @return A show instance for the {@link P6 tuple-6} type. + */ + public static Show> p6Show(final Show sa, final Show sb, + final Show sc, final Show sd, + final Show se, final Show sf) { + return new Show>(new F, Stream>() { + public Stream f(final P6 p) { + return cons('(', p(sa.show(p._1()))).snoc(',').append(sb.show(p._2())).snoc(',') + .append(sc.show(p._3())).snoc(',').append(sd.show(p._4())).snoc(',') + .append(se.show(p._5())).snoc(',').append(sf.show(p._6())).snoc(')'); + } + }); + } + + /** + * A show instance for the {@link P7 tuple-7} type. + * + * @param sa Show for the first element of the tuple. + * @param sb Show for the second element of the tuple. + * @param sc Show for the third element of the tuple. + * @param sd Show for the fourth element of the tuple. + * @param se Show for the fifth element of the tuple. + * @param sf Show for the sixth element of the tuple. + * @param sg Show for the seventh element of the tuple. + * @return A show instance for the {@link P7 tuple-7} type. + */ + public static Show> p7Show(final Show sa, final Show sb, + final Show sc, final Show sd, + final Show se, final Show sf, + final Show sg) { + return new Show>(new F, Stream>() { + public Stream f(final P7 p) { + return cons('(', p(sa.show(p._1()))).snoc(',').append(sb.show(p._2())).snoc(',') + .append(sc.show(p._3())).snoc(',').append(sd.show(p._4())).snoc(',') + .append(se.show(p._5())).snoc(',').append(sf.show(p._6())).snoc(',').append(sg.show(p._7())).snoc(')'); + } + }); + } + + /** + * A show instance for the {@link P8 tuple-8} type. + * + * @param sa Show for the first element of the tuple. + * @param sb Show for the second element of the tuple. + * @param sc Show for the third element of the tuple. + * @param sd Show for the fourth element of the tuple. + * @param se Show for the fifth element of the tuple. + * @param sf Show for the sixth element of the tuple. + * @param sg Show for the seventh element of the tuple. + * @param sh Show for the eighth element of the tuple. + * @return A show instance for the {@link P8 tuple-8} type. + */ + public static Show> p8Show(final Show sa, final Show sb, + final Show sc, final Show sd, + final Show se, final Show sf, + final Show sg, final Show sh) { + return new Show>(new F, Stream>() { + public Stream f(final P8 p) { + return cons('(', p(sa.show(p._1()))).snoc(',').append(sb.show(p._2())).snoc(',') + .append(sc.show(p._3())).snoc(',').append(sd.show(p._4())).snoc(',') + .append(se.show(p._5())).snoc(',').append(sf.show(p._6())).snoc(',') + .append(sg.show(p._7())).snoc(',').append(sh.show(p._8())).snoc(')'); + } + }); + } + + /** + * A show instance for a vector-2. + * + * @param ea A show for the elements of the vector. + * @return A show instance for a vector-2. + */ + public static Show> v2Show(final Show ea) { + return streamShow(ea).comap(V2.toStream_()); + } + + /** + * A show instance for a vector-3. + * + * @param ea A show for the elements of the vector. + * @return A show instance for a vector-3. + */ + public static Show> v3Show(final Show ea) { + return streamShow(ea).comap(V3.toStream_()); + } + + /** + * A show instance for a vector-4. + * + * @param ea A show for the elements of the vector. + * @return A show instance for a vector-4. + */ + public static Show> v4Show(final Show ea) { + return streamShow(ea).comap(V4.toStream_()); + } + + /** + * A show instance for a vector-5. + * + * @param ea A show for the elements of the vector. + * @return A show instance for a vector-5. + */ + public static Show> v5Show(final Show ea) { + return streamShow(ea).comap(V5.toStream_()); + } + + /** + * A show instance for a vector-6. + * + * @param ea A show for the elements of the vector. + * @return A show instance for a vector-6. + */ + public static Show> v6Show(final Show ea) { + return streamShow(ea).comap(V6.toStream_()); + } + + /** + * A show instance for a vector-7. + * + * @param ea A show for the elements of the vector. + * @return A show instance for a vector-7. + */ + public static Show> v7Show(final Show ea) { + return streamShow(ea).comap(V7.toStream_()); + } + + /** + * A show instance for a vector-8. + * + * @param ea A show for the elements of the vector. + * @return A show instance for a vector-8. + */ + public static Show> v8Show(final Show ea) { + return streamShow(ea).comap(V8.toStream_()); + } + + /** + * A show instance for natural numbers. + */ + public static final Show naturalShow = bigintShow.comap(new F() { + public BigInteger f(final Natural natural) { + return natural.bigIntegerValue(); + } + }); + + /** + * A show instance for streams that splits into lines. + * + * @param sa A show instance for the elements of a stream. + * @return A show instance for streams that splits into lines. + */ + public static Show> unlineShow(final Show sa) { + return new Show>(new F, Stream>() { + public Stream f(final Stream as) { + return join(as.map(sa.show_()).intersperse(fromString("\n"))); + } + }); + } + + /** + * A show instance for lazy strings. + */ + public static final Show lazyStringShow = show(new F>() { + public Stream f(final LazyString string) { + return string.toStream(); + } + }); + + /** + * A show instance for the empty heterogeneous Stream. + */ + public static final Show HListShow = showS(Function.constant("Nil")); + + /** + * A show instance for heterogeneous Streams. + * + * @param e A show instance for the first element of the Stream. + * @param l A show instance for the rest of the Stream. + * @return a show instance for heterogeneous Streams. + */ + public static > Show> HListShow(final Show e, final Show l) { + return show(new F, Stream>() { + public Stream f(final HList.HCons c) { + return e.show(c.head()).cons('[').append(l.show(c.tail())).snoc(']'); + } + }); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Try.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/Try.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,166 @@ +package fj; + +import fj.data.IO; +import fj.data.IOFunctions; +import fj.data.Validation; +import fj.function.*; + +import java.io.IOException; + +import static fj.data.Validation.fail; +import static fj.data.Validation.success; + +/** + * Created by mperry on 24/07/2014. + */ +public class Try { + + /** + * Promotes the TryCatch0 to a Validation that returns an Exception on the failure side and its result on the success side. + * + * @param t A TryCatch0 to promote + * @return A Validation with an Exception on the failure side and its result on the success side. + */ + static public P1> f(final Try0 t) { + return P.lazy(u -> { + try { + return Validation.success(t.f()); + } catch (Exception e) { + return Validation.fail((E) e); + } + }); + } + + /** + * Promotes the TryCatch1 to a Validation that returns an Exception on the failure side and its result on the success side. + * + * @param t A TryCatch1 to promote + * @return A Validation with an Exception on the failure side and its result on the success side. + */ + static public F> f(final Try1 t) { + return a -> { + try { + return Validation.success(t.f(a)); + } catch (Exception e) { + return Validation.fail((E) e); + } + }; + } + + /** + * Promotes the TryCatch2 to a Validation that returns an Exception on the failure side and its result on the success side. + * + * @param t A TryCatch2 to promote + * @return A Validation with an Exception on the failure side and its result on the success side. + */ + static public F2> f(final Try2 t) { + return (a, b) -> { + try { + return Validation.success(t.f(a, b)); + } catch (Exception e) { + return Validation.fail((E) e); + } + }; + } + + /** + * Promotes the TryCatch3 to a Validation that returns an Exception on the failure side and its result on the success side. + * + * @param t A TryCatch3 to promote + * @return A Validation with an Exception on the failure side and its result on the success side. + */ + static public F3> f(final Try3 t) { + return (a, b, c) -> { + try { + return success(t.f(a, b, c)); + } catch (Exception e) { + return fail((E) e); + } + }; + } + + /** + * Promotes the TryCatch4 to a Validation that returns an Exception on the failure side and its result on the success side. + * + * @param t A TryCatch4 to promote + * @return A Validation with an Exception on the failure side and its result on the success side. + */ + static public F4> f(final Try4 t) { + return (a, b, c, d) -> { + try { + return Validation.success(t.f(a, b, c, d)); + } catch (Exception ex) { + return Validation.fail((Z) ex); + } + }; + } + + /** + * Promotes the TryCatch5 to a Validation that returns an Exception on the failure side and its result on the success side. + * + * @param t A TryCatch5 to promote + * @return A Validation with an Exception on the failure side and its result on the success side. + */ + static public F5> f(final Try5 t) { + return (a, b, c, d, e) -> { + try { + return Validation.success(t.f(a, b, c, d, e)); + } catch (Exception ex) { + return Validation.fail((Z) ex); + } + }; + } + + /** + * Promotes the TryCatch6 to a Validation that returns an Exception on the failure side and its result on the success side. + * + * @param t A TryCatch6 to promote + * @return A Validation with an Exception on the failure side and its result on the success side. + */ + static public F6> f(final Try6 t) { + return (a, b, c, d, e, f) -> { + try { + return Validation.success(t.f(a, b, c, d, e, f)); + } catch (Exception ex) { + return Validation.fail((Z) ex); + } + }; + } + + /** + * Promotes the TryCatch7 to a Validation that returns an Exception on the failure side and its result on the success side. + * + * @param t A TryCatch7 to promote + * @return A Validation with an Exception on the failure side and its result on the success side. + */ + static public F7> f(final Try7 t) { + return (a, b, c, d, e, f, g) -> { + try { + return Validation.success(t.f(a, b, c, d, e, f, g)); + } catch (Exception ex) { + return Validation.fail((Z) ex); + } + }; + } + + /** + * Promotes the TryCatch8 to a Validation that returns an Exception on the failure side and its result on the success side. + * + * @param t A TryCatch8 to promote + * @return A Validation with an Exception on the failure side and its result on the success side. + */ + static public F8> f(final Try8 t) { + return (a, b, c, d, e, f, g, h) -> { + try { + return Validation.success(t.f(a, b, c, d, e, f, g, h)); + } catch (Exception ex) { + return Validation.fail((Z) ex); + } + }; + } + + public static IO io(Try0 t) { + return IOFunctions.io(t); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/TryEffect.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/TryEffect.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,118 @@ +package fj; + +import fj.data.IO; +import fj.data.IOFunctions; +import fj.data.Validation; +import fj.function.*; + +import java.io.IOException; + +/** + * Created by mperry on 29/08/2014. + */ +public class TryEffect { + + private TryEffect(){} + + public static P1> f(TryEffect0 t) { + return P.lazy(u -> { + try { + t.f(); + return Validation.success(Unit.unit()); + } catch (Exception e) { + return Validation.fail((Z) e); + } + }); + } + + public static F> f(TryEffect1 t) { + return a -> { + try { + t.f(a); + return Validation.success(Unit.unit()); + } catch (Exception e) { + return Validation.fail((Z) e); + } + }; + + } + + public static F2> f(TryEffect2 t) { + return (a, b) -> { + try { + t.f(a, b); + return Validation.success(Unit.unit()); + } catch (Exception e) { + return Validation.fail((Z) e); + } + }; + + } + + public static F3> f(TryEffect3 t) { + return (a, b, c) -> { + try { + t.f(a, b, c); + return Validation.success(Unit.unit()); + } catch (Exception e) { + return Validation.fail((Z) e); + } + }; + } + + public static F4> f(TryEffect4 t) { + return (a, b, c, d) -> { + try { + t.f(a, b, c, d); + return Validation.success(Unit.unit()); + } catch (Exception e) { + return Validation.fail((Z) e); + } + }; + } + + public static F5> f(TryEffect5 t) { + return (a, b, c, d, e) -> { + try { + t.f(a, b, c, d, e); + return Validation.success(Unit.unit()); + } catch (Exception z) { + return Validation.fail((Z) z); + } + }; + } + + public static F6> f(TryEffect6 t) { + return (a, b, c, d, e, f) -> { + try { + t.f(a, b, c, d, e, f); + return Validation.success(Unit.unit()); + } catch (Exception z) { + return Validation.fail((Z) z); + } + }; + } + + public static F7> f(TryEffect7 t) { + return (a, b, c, d, e, f, g) -> { + try { + t.f(a, b, c, d, e, f, g); + return Validation.success(Unit.unit()); + } catch (Exception z) { + return Validation.fail((Z) z); + } + }; + } + + public static F8> f(TryEffect8 t) { + return (a, b, c, d, e, f, g, h) -> { + try { + t.f(a, b, c, d, e, f, g, h); + return Validation.success(Unit.unit()); + } catch (Exception z) { + return Validation.fail((Z) z); + } + }; + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/Unit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/Unit.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,23 @@ +package fj; + +/** + * The unit type which has only one value. + * + * @version %build.number% + */ +public final class Unit { + private static final Unit u = new Unit(); + + private Unit() { + + } + + /** + * The only value of the unit type. + * + * @return The only value of the unit type. + */ + public static Unit unit() { + return u; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/control/Trampoline.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/control/Trampoline.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,372 @@ +package fj.control; + +import fj.Bottom; +import fj.F; +import fj.F1Functions; +import fj.F2; +import fj.P1; +import fj.data.Either; +import fj.F2Functions; +import static fj.Function.curry; +import static fj.data.Either.left; +import static fj.data.Either.right; + +/** + * A Trampoline is a potentially branching computation that can be stepped through and executed in constant stack. + * It represent suspendable coroutines with subroutine calls, reified as a data structure. + */ +public abstract class Trampoline { + + // A Normal Trampoline is either done or suspended, and is allowed to be a subcomputation of a Codense. + // This is the pointed functor part of the Trampoline monad. + private static abstract class Normal extends Trampoline { + public abstract R foldNormal(final F pure, final F>, R> k); + + public Trampoline bind(final F> f) { + return codense(this, f); + } + } + + // A Codense Trampoline delimits a subcomputation and tracks its current continuation. Subcomputations are only + // allowed to be Normal, so all of the continuations accumulate on the right. + private static final class Codense extends Trampoline { + + // The Normal subcomputation + private final Normal sub; + + // The current continuation + private final F> cont; + + private Codense(final Normal t, final F> k) { + sub = t; + cont = k; + } + + public R fold(final F, R> n, + final F, R> gs) { + return gs.f(this); + } + + // The monadic bind constructs a new Codense whose subcomputation is still `sub`, and Kleisli-composes the + // continuations. + public Trampoline bind(final F> f) { + return codense(sub, new F>() { + public Trampoline f(final Object o) { + return suspend(new P1>() { + public Trampoline _1() { + return cont.f(o).bind(f); + } + }); + } + }); + } + + // The resumption of a Codense is the resumption of its subcomputation. If that computation is done, its result + // gets shifted into the continuation. + public Either>, A> resume() { + return left(sub.resume().either(new F>, P1>>() { + public P1> f(final P1> p) { + return p.map(new F, Trampoline>() { + public Trampoline f(final Trampoline ot) { + return ot.fold(new F, Trampoline>() { + public Trampoline f(final Normal o) { + return o.foldNormal(new F>() { + public Trampoline f(final Object o) { + return cont.f(o); + } + }, new F>, Trampoline>() { + public Trampoline f(final P1> t) { + return t._1().bind(cont); + } + } + ); + } + }, new F, Trampoline>() { + public Trampoline f(final Codense c) { + return codense(c.sub, new F>() { + public Trampoline f(final Object o) { + return c.cont.f(o).bind(cont); + } + }); + } + } + ); + } + }); + } + }, new F>>() { + public P1> f(final Object o) { + return new P1>() { + public Trampoline _1() { + return cont.f(o); + } + }; + } + } + )); + } + } + + // A suspended computation that can be resumed. + private static final class Suspend extends Normal { + + private final P1> suspension; + + private Suspend(final P1> s) { + suspension = s; + } + + public R foldNormal(final F pure, final F>, R> k) { + return k.f(suspension); + } + + public R fold(final F, R> n, final F, R> gs) { + return n.f(this); + } + + public Either>, A> resume() { + return left(suspension); + } + } + + // A pure value at the leaf of a computation. + private static final class Pure extends Normal { + private final A value; + + private Pure(final A a) { + value = a; + } + + public R foldNormal(final F pure, final F>, R> k) { + return pure.f(value); + } + + public R fold(final F, R> n, final F, R> gs) { + return n.f(this); + } + + public Either>, A> resume() { + return right(value); + } + } + + @SuppressWarnings("unchecked") + protected static Codense codense(final Normal a, final F> k) { + return new Codense((Normal) a, (F>) k); + } + + /** + * @return The first-class version of `pure`. + */ + public static F> pure() { + return new F>() { + public Trampoline f(final A a) { + return pure(a); + } + }; + } + + /** + * Constructs a pure computation that results in the given value. + * + * @param a The value of the result. + * @return A trampoline that results in the given value. + */ + public static Trampoline pure(final A a) { + return new Pure(a); + } + + /** + * Suspends the given computation in a thunk. + * + * @param a A trampoline suspended in a thunk. + * @return A trampoline whose next step runs the given thunk. + */ + public static Trampoline suspend(final P1> a) { + return new Suspend(a); + } + + /** + * @return The first-class version of `suspend`. + */ + public static F>, Trampoline> suspend_() { + return new F>, Trampoline>() { + public Trampoline f(final P1> trampolineP1) { + return suspend(trampolineP1); + } + }; + } + + protected abstract R fold(final F, R> n, final F, R> gs); + + /** + * Binds the given continuation to the result of this trampoline. + * + * @param f A function that constructs a trampoline from the result of this trampoline. + * @return A new trampoline that runs this trampoline, then continues with the given function. + */ + public abstract Trampoline bind(final F> f); + + /** + * Maps the given function across the result of this trampoline. + * + * @param f A function that gets applied to the result of this trampoline. + * @return A new trampoline that runs this trampoline, then applies the given function to the result. + */ + public final Trampoline map(final F f) { + return bind(F1Functions.o(Trampoline.pure(), f)); + } + + /** + * @return The first-class version of `bind`. + */ + public static F>, F, Trampoline>> bind_() { + return new F>, F, Trampoline>>() { + public F, Trampoline> f(final F> f) { + return new F, Trampoline>() { + public Trampoline f(final Trampoline a) { + return a.bind(f); + } + }; + } + }; + } + + /** + * @return The first-class version of `map`. + */ + public static F, F, Trampoline>> map_() { + return new F, F, Trampoline>>() { + public F, Trampoline> f(final F f) { + return new F, Trampoline>() { + public Trampoline f(final Trampoline a) { + return a.map(f); + } + }; + } + }; + } + + /** + * @return The first-class version of `resume`. + */ + public static F, Either>, A>> resume_() { + return new F, Either>, A>>() { + public Either>, A> f(final Trampoline aTrampoline) { + return aTrampoline.resume(); + } + }; + } + + /** + * Runs a single step of this computation. + * + * @return The next step of this compuation. + */ + public abstract Either>, A> resume(); + + /** + * Runs this computation all the way to the end, in constant stack. + * + * @return The end result of this computation. + */ + @SuppressWarnings("LoopStatementThatDoesntLoop") + public A run() { + Trampoline current = this; + while (true) { + final Either>, A> x = current.resume(); + for (final P1> t : x.left()) { + current = t._1(); + } + for (final A a : x.right()) { + return a; + } + } + } + + /** + * Performs function application within a Trampoline (applicative functor pattern). + * + * @param lf A Trampoline resulting in the function to apply. + * @return A new Trampoline after applying the given function through this Trampoline. + */ + public final Trampoline apply(final Trampoline> lf) { + return lf.bind(new F, Trampoline>() { + public Trampoline f(final F f) { + return map(f); + } + }); + } + + /** + * Binds the given function across the result of this Trampoline and the given Trampoline. + * + * @param lb A given Trampoline to bind the given function with. + * @param f The function to combine the results of this Trampoline and the given Trampoline. + * @return A new Trampoline combining the results of the two trampolines with the given function. + */ + public final Trampoline bind(final Trampoline lb, final F> f) { + return lb.apply(map(f)); + } + + + /** + * Promotes the given function of arity-2 to a function on Trampolines. + * + * @param f The function to promote to a function on Trampolines. + * @return The given function, promoted to operate on Trampolines. + */ + public static F, F, Trampoline>> liftM2(final F> f) { + return curry(new F2, Trampoline, Trampoline>() { + public Trampoline f(final Trampoline as, final Trampoline bs) { + return as.bind(bs, f); + } + }); + } + + /** + * Combines two trampolines so they run cooperatively. The results are combined with the given function. + * + * @param b Another trampoline to combine with this trampoline. + * @param f A function to combine the results of the two trampolines. + * @return A new trampoline that runs this trampoline and the given trampoline simultaneously. + */ + @SuppressWarnings("LoopStatementThatDoesntLoop") + public Trampoline zipWith(final Trampoline b, final F2 f) { + final Either>, A> ea = resume(); + final Either>, B> eb = b.resume(); + for (final P1> x : ea.left()) { + for (final P1> y : eb.left()) { + return suspend(x.bind(y, F2Functions.curry(new F2, Trampoline, Trampoline>() { + public Trampoline f(final Trampoline ta, final Trampoline tb) { + return suspend(new P1>() { + public Trampoline _1() { + return ta.zipWith(tb, f); + } + }); + } + }))); + } + for (final B y : eb.right()) { + return suspend(x.map(new F, Trampoline>() { + public Trampoline f(final Trampoline ta) { + return ta.map(F2Functions.f(F2Functions.flip(f), y)); + } + })); + } + } + for (final A x : ea.right()) { + for (final B y : eb.right()) { + return suspend(new P1>() { + public Trampoline _1() { + return pure(f.f(x, y)); + } + }); + } + for (final P1> y : eb.left()) { + return suspend(y.map(liftM2(F2Functions.curry(f)).f(pure(x)))); + } + } + throw Bottom.error("Match error: Trampoline is neither done nor suspended."); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/control/db/Connector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/control/db/Connector.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,11 @@ +package fj.control.db; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * A method of connecting to the database. + */ +public abstract class Connector { + public abstract Connection connect() throws SQLException; +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/control/db/DB.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/control/db/DB.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,120 @@ +package fj.control.db; + +import fj.F; +import fj.Function; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.concurrent.Callable; + +/** + * The DB monad represents a database action, or a value within the context of a database connection. + */ +public abstract class DB { + + /** + * Executes the database action, given a database connection. + * + * @param c The connection against which to execute the action. + * @return The result of the action. + * @throws SQLException if a database error occurred. + */ + public abstract A run(final Connection c) throws SQLException; + + /** + * Constructs a database action as a function from a database connection to a value. + * + * @param f A function from a database connection to a value. + * @return A database action representing the given function. + */ + public static DB db(final F f) { + return new DB() { + public A run(final Connection c) { + return f.f(c); + } + }; + } + + /** + * Returns the callable-valued function projection of this database action. + * + * @return The callable-valued function which is isomorphic to this database action. + */ + public final F> asFunction() { + return new F>() { + public Callable f(final Connection c) { + return new Callable() { + public A call() throws Exception { + return run(c); + } + }; + } + }; + } + + /** + * Map a function over the result of this action. + * + * @param f The function to map over the result. + * @return A new database action that applies the given function to the result of this action. + */ + public final DB map(final F f) { + return new DB() { + public B run(final Connection c) throws SQLException { + return f.f(DB.this.run(c)); + } + }; + } + + /** + * Promotes any given function so that it transforms between values in the database. + * + * @param f The function to promote. + * @return A function equivalent to the given one, which operates on values in the database. + */ + public static F, DB> liftM(final F f) { + return new F, DB>() { + public DB f(final DB a) { + return a.map(f); + } + }; + } + + /** + * Constructs a database action that returns the given value completely intact. + * + * @param a A value to be wrapped in a database action. + * @return A new database action that returns the given value. + */ + public static DB unit(final A a) { + return new DB() { + public A run(final Connection c) { + return a; + } + }; + } + + /** + * Binds the given action across the result of this database action. + * + * @param f The function to bind across the result of this database action. + * @return A new database action equivalent to applying the given function to the result of this action. + */ + public final DB bind(final F> f) { + return new DB() { + public B run(final Connection c) throws SQLException { + return f.f(DB.this.run(c)).run(c); + } + }; + } + + /** + * Removes one layer of monadic structure. + * + * @param a A database action that results in another. + * @return A new database action equivalent to the result of the given action. + */ + public static DB join(final DB> a) { + return a.bind(Function.>identity()); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/control/db/DbState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/control/db/DbState.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,111 @@ +package fj.control.db; + +import fj.Unit; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** + * Performs database I/O, in order to read or write the database state. + */ +public final class DbState { + private final Connector pc; + private final DB terminal; + + private DbState(final Connector pc, final DB terminal) { + this.pc = pc; + this.terminal = terminal; + } + + /** + * A simple connector (the default) that gets connections to the given database URL from the driver manager. + * + * @param url The database URL to connect to. + * @return A connector that generates connections to the given database. + */ + public static Connector driverManager(final String url) { + return new Connector() { + public Connection connect() throws SQLException { + return DriverManager.getConnection(url); + } + }; + } + + /** + * Creates a database state reader given a connection URL. + * + * @param url The connection URL to the database. + * @return A database state reader that reads the given database. + */ + public static DbState reader(final String url) { + return new DbState(driverManager(url), rollback); + } + + /** + * Creates a database state writer given a connection URL. + * + * @param url The connection URL to the database. + * @return A database state writer that writes the given database. + */ + public static DbState writer(final String url) { + return new DbState(driverManager(url), commit); + } + + /** + * Returns a new reader that reads the database via the given Connector. + * + * @param pc A connector with which to generate database connections. + * @return A new reader that reads the database via the given Connector. + */ + public static DbState reader(final Connector pc) { + return new DbState(pc, rollback); + } + + /** + * Returns a new writer that writes the database via the given Connector. + * + * @param pc A connector with which to generate database connections. + * @return A new writer that writes the database via the given Connector. + */ + public static DbState writer(final Connector pc) { + return new DbState(pc, commit); + } + + private static final DB rollback = new DB() { + public Unit run(final Connection c) throws SQLException { + c.rollback(); + return Unit.unit(); + } + }; + + private static final DB commit = new DB() { + public Unit run(final Connection c) throws SQLException { + c.commit(); + return Unit.unit(); + } + }; + + /** + * Runs the given database action as a single transaction. + * + * @param dba A database action to run. + * @return The result of running the action against the database. + * @throws SQLException in case of a database error. + */ + public A run(final DB dba) throws SQLException { + final Connection c = pc.connect(); + c.setAutoCommit(false); + try { + final A a = dba.run(c); + terminal.run(c); + return a; + } catch (SQLException e) { + c.rollback(); + throw e; + } + finally { + c.close(); + } + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/control/db/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/control/db/package-info.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,4 @@ +/** + * Abstractions for JDBC connections. + */ +package fj.control.db; diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/control/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/control/package-info.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,4 @@ +/** + * Functional control abstractions. + */ +package fj.control; diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/control/parallel/Actor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/control/parallel/Actor.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,150 @@ +package fj.control.parallel; + +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; + +import fj.Effect; +import fj.F; +import fj.Unit; +import fj.P1; +import fj.function.Effect1; + +/** + * Light weight actors for Java. Concurrency is controlled by a parallel Strategy. + * The Strategy serves as the Actor's execution engine, and as its mailbox. + *

+ * Given some effect, the Actor performs the effect on its messages using its Strategy, transforming them + * into instances of fj.P1. The P1 represents a possibly running computation which is executing the effect. + *

+ * NOTE: A value of this type may generally process more than one message at a time, depending on its Strategy. + * An actor is not thread-safe unless either its Effect imposes an order on incoming messages or its Strategy is + * single-threaded. + * + * A queue actor which imposes an order on its messages is provided by the {@link #queueActor} static method. + */ +public final class Actor { + + private final Strategy s; + private final F> f; + + /** + * An Actor equipped with a queue and which is guaranteed to process one message at a time. + * With respect to an enqueueing actor or thread, this actor will process messages in the same order + * as they are sent. + */ + public static Actor queueActor(final Strategy s, final Effect1 ea) { + return actor(Strategy.seqStrategy(), new Effect1() { + + // Lock to ensure the actor only acts on one message at a time + AtomicBoolean suspended = new AtomicBoolean(true); + + // Queue to hold pending messages + ConcurrentLinkedQueue mbox = new ConcurrentLinkedQueue(); + + // Product so the actor can use its strategy (to act on messages in other threads, + // to handle exceptions, etc.) + P1 processor = new P1() { + @Override public Unit _1() { + // get next item from queue + T a = mbox.poll(); + // if there is one, process it + if (a != null) { + ea.f(a); + // try again, in case there are more messages + s.par(this); + } else { + // clear the lock + suspended.set(true); + // work again, in case someone else queued up a message while we were holding the lock + work(); + } + return Unit.unit(); + } + }; + + // Effect's body -- queues up a message and tries to unsuspend the actor + @Override public void f(T a) { + mbox.offer(a); + work(); + } + + // If there are pending messages, use the strategy to run the processor + protected void work() { + if (!mbox.isEmpty() && suspended.compareAndSet(true, false)) { + s.par(processor); + } + } + }); + }; + + private Actor(final Strategy s, final F> e) { + this.s = s; + f = new F>() { + public P1 f(final A a) { + return s.par(e.f(a)); + } + }; + } + + /** + * Creates a new Actor that uses the given parallelization strategy and has the given side-effect. + * + * @param s The parallelization strategy to use for the new Actor. + * @param e The side-effect to apply to messages passed to the Actor. + * @return A new actor that uses the given parallelization strategy and has the given side-effect. + */ + public static Actor actor(final Strategy s, final Effect1 e) { + return new Actor(s, P1.curry(Effect.f(e))); + } + + /** + * Creates a new Actor that uses the given parallelization strategy and has the given side-effect. + * + * @param s The parallelization strategy to use for the new Actor. + * @param e The function projection of a side-effect to apply to messages passed to the Actor. + * @return A new actor that uses the given parallelization strategy and has the given side-effect. + */ + public static Actor actor(final Strategy s, final F> e) { + return new Actor(s, e); + } + + /** + * Pass a message to this actor, applying its side-effect to the message. The side-effect is applied in a concurrent + * computation, resulting in a product referencing that computation. + * + * @param a The message to send to this actor. + * @return A unit-product that represents the action running concurrently. + */ + public P1 act(final A a) { + return f.f(a); + } + + /** + * Contravariant functor pattern. Creates a new actor whose message is transformed by the given function + * before being passed to this actor. + * + * @param f The function to use for the transformation + * @return A new actor which passes its messages through the given function, to this actor. + */ + public Actor comap(final F f) { + return actor(s, new F>() { + public P1 f(final B b) { + return act(f.f(b)); + } + }); + } + + /** + * Transforms this actor to an actor on promises. + * + * @return A new actor, equivalent to this actor, that acts on promises. + */ + public Actor> promise() { + return actor(s, new Effect1>() { + public void f(final Promise b) { + b.to(Actor.this); + } + }); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/control/parallel/Callables.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/control/parallel/Callables.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,359 @@ +package fj.control.parallel; + +import fj.F; +import fj.F2; +import fj.Function; +import static fj.Function.curry; +import fj.P1; +import fj.data.Either; +import static fj.data.Either.left; +import static fj.data.Either.right; +import fj.data.List; +import fj.data.Option; +import static fj.data.Option.none; +import static fj.data.Option.some; + +import java.util.concurrent.Callable; + +/** + * Monadic functions and conversion methods for java.util.concurrent.Callable. + * + * @version %build.number% + */ +public final class Callables { + private Callables() { + } + + /** + * Returns a callable that completely preserves the argument. The unit function for Callables. + * + * @param a A value to preserve in a Callable + * @return A Callable that yields the argument when called. + */ + public static Callable callable(final A a) { + return new Callable() { + public A call() throws Exception { + return a; + } + }; + } + + /** + * Returns a callable that throws the given exception. The unit function for Callables. + * + * @param e The exception to throw when the Callable is called. + * @return A callable that always throws the given exception. + */ + public static Callable callable(final Exception e) { + return new Callable() { + public A call() throws Exception { + throw e; + } + }; + } + + /** + * Provides a transformation from a value to a Callable that completely preserves that value. + * + * @return A function from a value to a Callable that completely preserves that value. + */ + public static F> callable() { + return new F>() { + public Callable f(final A a) { + return callable(a); + } + }; + } + + /** + * Wraps a given function's return value in a Callable. + * The Kleisli arrow for Callables. + * + * @param f The function whose return value to wrap in a Callable. + * @return The equivalent function whose return value is wrapped in a Callable. + */ + public static F> callable(final F f) { + return new F>() { + public Callable f(final A a) { + return new Callable() { + public B call() { + return f.f(a); + } + }; + } + }; + } + + /** + * Provides a transformation from a function to a Callable-valued function that is equivalent to it. + * The first-class Kleisli arrow for Callables. + * + * @return A transformation from a function to the equivalent Callable-valued function. + */ + public static F, F>> arrow() { + return new F, F>>() { + public F> f(final F f) { + return callable(f); + } + }; + } + + /** + * Binds the given function to the value in a Callable with a final join. + * + * @param a A value in a Callable to which to apply a function. + * @param f A function to apply to the value in a Callable. + * @return The result of applying the function in the second argument to the value of the Callable in the first. + */ + public static Callable bind(final Callable a, final F> f) { + return new Callable() { + public B call() throws Exception { + return f.f(a.call()).call(); + } + }; + } + + /** + * Lifts any function to a function on Callables. + * + * @param f A function to lift to a function on Callables. + * @return That function lifted to a function on Callables. + */ + public static F, Callable> fmap(final F f) { + return new F, Callable>() { + public Callable f(final Callable a) { + return Callables.bind(a, callable(f)); + } + }; + } + + /** + * Performs function application within a callable (applicative functor pattern). + * + * @param ca The callable to which to apply a function. + * @param cf The callable function to apply. + * @return A new callable after applying the given callable function to the first argument. + */ + public static Callable apply(final Callable ca, final Callable> cf) { + return bind(cf, new F, Callable>() { + public Callable f(final F f) { + return fmap(f).f(ca); + } + }); + } + + /** + * Binds the given function to the values in the given callables with a final join. + * + * @param ca A given callable to bind the given function with. + * @param cb A given callable to bind the given function with. + * @param f The function to apply to the values in the given callables. + * @return A new callable after performing the map, then final join. + */ + public static Callable bind(final Callable ca, final Callable cb, final F> f) { + return apply(cb, fmap(f).f(ca)); + } + + /** + * Joins a Callable of a Callable with a bind operation. + * + * @param a The Callable of a Callable to join. + * @return A new Callable that is the join of the given Callable. + */ + public static Callable join(final Callable> a) { + return bind(a, Function.>identity()); + } + + /** + * Promotes a function of arity-2 to a function on callables. + * + * @param f The function to promote. + * @return A function of arity-2 promoted to map over callables. + */ + public static F, F, Callable>> liftM2(final F> f) { + return curry(new F2, Callable, Callable>() { + public Callable f(final Callable ca, final Callable cb) { + return bind(ca, cb, f); + } + }); + } + + /** + * Turns a List of Callables into a single Callable of a List. + * + * @param as The list of callables to transform. + * @return A single callable for the given List. + */ + public static Callable> sequence(final List> as) { + return as.foldRight(Callables., + List>liftM2(List.cons()), callable(List.nil())); + } + + /** + * A first-class version of the sequence method. + * + * @return A function from a List of Callables to a single Callable of a List. + */ + public static F>, Callable>> sequence_() { + return new F>, Callable>>() { + public Callable> f(final List> as) { + return sequence(as); + } + }; + } + + /** + * Turns the given Callable into an optional value. + * + * @param a The callable to convert to an optional value. + * @return An optional value that yields the value in the Callable, or None if the Callable fails. + */ + public static P1> option(final Callable a) { + return new P1>() { + @SuppressWarnings({"UnusedCatchParameter"}) + public Option _1() { + try { + return some(a.call()); + } catch (Exception e) { + return none(); + } + } + }; + } + + /** + * Returns a transformation from a Callable to an optional value. + * + * @return a function that turns a Callable into an optional value. + */ + public static F, P1>> option() { + return new F, P1>>() { + public P1> f(final Callable a) { + return option(a); + } + }; + } + + /** + * Turns the given Callable into either an exception or the value in the Callable. + * + * @param a The callable to convert to an Either value. + * @return Either the value in the given Callable, or the Exception with which the Callable fails. + */ + public static P1> either(final Callable a) { + return new P1>() { + public Either _1() { + try { + return right(a.call()); + } catch (Exception e) { + return left(e); + } + } + }; + } + + /** + * Returns a transformation from a Callable to an Either. + * + * @return a function that turns a Callable into an Either. + */ + public static F, P1>> either() { + return new F, P1>>() { + public P1> f(final Callable a) { + return either(a); + } + }; + } + + /** + * Turns a given Either value into the equivalent Callable. + * + * @param e Either an exception or a value to wrap in a Callable + * @return A Callable equivalent to the given Either value. + */ + public static Callable fromEither(final P1> e) { + return new Callable() { + public A call() throws Exception { + final Either e1 = e._1(); + if (e1.isLeft()) + throw e1.left().value(); + else + return e1.right().value(); + } + }; + } + + /** + * Returns a transformation from an Either to a Callable. + * + * @return a function that turns an Either into a Callable. + */ + public static F>, Callable> fromEither() { + return new F>, Callable>() { + public Callable f(final P1> e) { + return fromEither(e); + } + }; + } + + /** + * Turns an optional value into a Callable. + * + * @param o An optional value to turn into a Callable. + * @return A Callable that yields some value or throws an exception in the case of no value. + */ + public static Callable fromOption(final P1> o) { + return new Callable() { + public A call() throws Exception { + final Option o1 = o._1(); + if (o1.isSome()) + return o1.some(); + else + throw new Exception("No value."); + } + }; + } + + /** + * Returns a transformation from an optional value to a Callable + * + * @return A function that turns an optional value into a Callable that yields some value + * or throws an exception in the case of no value. + */ + public static F>, Callable> fromOption() { + return new F>, Callable>() { + public Callable f(final P1> o) { + return fromOption(o); + } + }; + } + + /** + * Normalises the given Callable by calling it and wrapping the result in a new Callable. + * If the given Callable throws an Exception, the resulting Callable will throw that same Exception. + * + * @param a The callable to evaluate. + * @return A normalised callable that just returns the result of calling the given callable. + */ + public static Callable normalise(final Callable a) { + try { + return callable(a.call()); + } catch (Exception e) { + return callable(e); + } + } + + /** + * A first-class version of the normalise function. + * + * @return A function that normalises the given Callable by calling it and wrapping the result in a new Callable. + */ + public static F, Callable> normalise() { + return new F, Callable>() { + public Callable f(final Callable a) { + return normalise(a); + } + }; + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/control/parallel/ParModule.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/control/parallel/ParModule.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,667 @@ +package fj.control.parallel; + +import fj.*; + +import static fj.P.p; +import static fj.Function.curry; +import static fj.Function.uncurryF2; +import static fj.control.parallel.Promise.liftM2; +import fj.data.Array; +import fj.data.IterableW; +import fj.data.List; +import fj.data.NonEmptyList; +import fj.data.Option; +import fj.data.Stream; +import fj.data.Tree; +import fj.data.TreeZipper; +import fj.data.Zipper; +import fj.function.Effect1; + +import static fj.data.Option.some; +import static fj.data.Stream.iterableStream; + +/** + * A module of higher-order concurrency features. + */ +public final class ParModule { + private final Strategy strategy; + + private ParModule(final Strategy strategy) { + this.strategy = strategy; + } + + /** + * Constructor method for ParModule + * + * @param u A parallel strategy for the module. + * @return A ParModule that uses the given strategy for parallelism. + */ + public static ParModule parModule(final Strategy u) { + return new ParModule(u); + } + + /** + * Evaluates the given product concurrently and returns a Promise of the result. + * + * @param p A product to evaluate concurrently. + * @return A Promise of the value of the given product, that can be claimed in the future. + */ + public Promise promise(final P1 p) { + return Promise.promise(strategy, p); + } + + /** + * Returns a function that evaluates a given product concurrently and returns a Promise of the result. + * + * @return a function that evaluates a given product concurrently and returns a Promise of the result. + */ + public F, Promise> promise() { + return new F, Promise>() { + public Promise f(final P1 ap1) { + return promise(ap1); + } + }; + } + + /** + * Promotes the given function to a concurrent function that returns a Promise. + * + * @param f A given function to promote to a concurrent function. + * @return A function that is applied concurrently when given an argument, yielding a Promise of the result + * that can be claimed in the future. + */ + public F> promise(final F f) { + return F1Functions.promiseK(f, strategy); + } + + /** + * Returns a function that promotes a given function to a concurrent function that returns a Promise. + * The pure Kleisli arrow of Promise. + * + * @return A higher-order function that takes pure functions to promise-valued functions. + */ + public F, F>> promisePure() { + return new F, F>>() { + public F> f(final F abf) { + return promise(abf); + } + }; + } + + /** + * Promotes the given function to a concurrent function that returns a Promise. + * + * @param f A given function to promote to a concurrent function. + * @return A function that is applied concurrently when given an argument, yielding a Promise of the result + * that can be claimed in the future. + */ + public F2> promise(final F2 f) { + return P2.untuple(F1Functions.promiseK(F2Functions.tuple(f), strategy)); + } + + + /** + * Creates a very fast concurrent effect, as an actor that does not guarantee ordering of its messages. + * Such an actor is not thread-safe unless the given Effect is. + * + * @param e The effect that the actor should have on its messages. + * @return A concurrent actor that does not guarantee ordering of its messages. + */ + public Actor effect(final Effect1 e) { + return Actor.actor(strategy, e); + } + + /** + * A first-class constructor of concurrent effects, as actors that don't guarantee ordering of messages. + * Such an actor is not thread-safe unless the given Effect is. + * + * @return A function that takes an effect and returns a concurrent effect. + */ + public F, Actor> effect() { + return new F, Actor>() { + public Actor f(final Effect1 effect) { + return effect(effect); + } + }; + } + + /** + * Creates a concurrent actor that is guaranteed to process only one message at a time. + * + * @param e The effect that the actor should have on its messages. + * @return A concurrent actor that is guaranteed to process its messages in order. + */ + public Actor actor(final Effect1 e) { + return Actor.queueActor(strategy, e); + } + + /** + * A first-class constructor of actors. + * + * @return A function that takes an effect and returns an actor that processes messages in some order. + */ + public F, Actor> actor() { + return new F, Actor>() { + public Actor f(final Effect1 effect) { + return actor(effect); + } + }; + } + + /** + * List iteration inside a Promise. Traverses a List of Promises yielding a Promise of a List. + * + * @param ps A list of promises to sequence. + * @return A promise of the List of values promised by the list of promises. + */ + public Promise> sequence(final List> ps) { + return Promise.sequence(strategy, ps); + } + + /** + * A first-class function that traverses a list inside a promise. + * + * @return A first-class function that traverses a list inside a promise. + */ + public F>, Promise>> sequenceList() { + return new F>, Promise>>() { + public Promise> f(final List> list) { + return sequence(list); + } + }; + } + + /** + * Stream iteration inside a Promise. Traverses a Stream of Promises yielding a Promise of a Stream. + * + * @param ps A Stream of promises to sequence. + * @return A promise of the Stream of values promised by the Stream of promises. + */ + public Promise> sequence(final Stream> ps) { + return Promise.sequence(strategy, ps); + } + + /** + * A first-class function that traverses a stream inside a promise. + * + * @return A first-class function that traverses a stream inside a promise. + */ + public F>, Promise>> sequenceStream() { + return new F>, Promise>>() { + public Promise> f(final Stream> stream) { + return sequence(stream); + } + }; + } + + /** + * Traverses a product-1 inside a promise. + * + * @param p A product-1 of a promised value. + * @return A promise of a product of the value promised by the argument. + */ + public Promise> sequence(final P1> p) { + return Promise.sequence(strategy, p); + } + + /** + * Takes a Promise-valued function and applies it to each element + * in the given List, yielding a promise of a List of results. + * + * @param as A list to map across. + * @param f A promise-valued function to map across the list. + * @return A Promise of a new list with the given function applied to each element. + */ + public Promise> mapM(final List as, final F> f) { + return sequence(as.map(f)); + } + + /** + * First-class function that maps a concurrent function over a List inside a promise. + * + * @return a function that maps a concurrent function over a List inside a promise. + */ + public F>, F, Promise>>> mapList() { + return curry(new F2>, List, Promise>>() { + public Promise> f(final F> f, final List list) { + return mapM(list, f); + } + }); + } + + /** + * Takes a Promise-valued function and applies it to each element + * in the given Stream, yielding a promise of a Stream of results. + * + * @param as A Stream to map across. + * @param f A promise-valued function to map across the Stream. + * @return A Promise of a new Stream with the given function applied to each element. + */ + public Promise> mapM(final Stream as, final F> f) { + return sequence(as.map(f)); + } + + /** + * First-class function that maps a concurrent function over a Stream inside a promise. + * + * @return a function that maps a concurrent function over a Stream inside a promise. + */ + public F>, F, Promise>>> mapStream() { + return curry(new F2>, Stream, Promise>>() { + public Promise> f(final F> f, final Stream stream) { + return mapM(stream, f); + } + }); + } + + /** + * Maps a concurrent function over a Product-1 inside a Promise. + * + * @param a A product-1 across which to map. + * @param f A concurrent function to map over the product inside a promise. + * @return A promised product of the result of mapping the given function over the given product. + */ + public Promise> mapM(final P1 a, final F> f) { + return sequence(a.map(f)); + } + + /** + * Maps across a list in parallel. + * + * @param as A list to map across in parallel. + * @param f A function to map across the given list. + * @return A Promise of a new list with the given function applied to each element. + */ + public Promise> parMap(final List as, final F f) { + return mapM(as, promise(f)); + } + + /** + * A first-class function that maps another function across a list in parallel. + * + * @return A function that maps another function across a list in parallel. + */ + public F, F, Promise>>> parMapList() { + return curry(new F2, List, Promise>>() { + public Promise> f(final F abf, final List list) { + return parMap(list, abf); + } + }); + } + + /** + * Maps across a nonempty list in parallel. + * + * @param as A NonEmptyList to map across in parallel. + * @param f A function to map across the given NonEmptyList. + * @return A Promise of a new NonEmptyList with the given function applied to each element. + */ + public Promise> parMap(final NonEmptyList as, final F f) { + return mapM(as.toList(), promise(f)).fmap(new F, NonEmptyList>() { + public NonEmptyList f(final List list) { + return NonEmptyList.fromList(list).some(); + } + }); + } + + /** + * Maps across a Stream in parallel. + * + * @param as A Stream to map across in parallel. + * @param f A function to map across the given Stream. + * @return A Promise of a new Stream with the given function applied to each element. + */ + public Promise> parMap(final Stream as, final F f) { + return mapM(as, promise(f)); + } + + /** + * A first-class function that maps another function across a stream in parallel. + * + * @return A function that maps another function across a stream in parallel. + */ + public F, F, Promise>>> parMapStream() { + return curry(new F2, Stream, Promise>>() { + public Promise> f(final F abf, final Stream stream) { + return parMap(stream, abf); + } + }); + } + + /** + * Maps across an Iterable in parallel. + * + * @param as An Iterable to map across in parallel. + * @param f A function to map across the given Iterable. + * @return A Promise of a new Iterable with the given function applied to each element. + */ + public Promise> parMap(final Iterable as, final F f) { + return parMap(iterableStream(as), f) + .fmap(Function., Iterable>vary(Function.>identity())); + } + + /** + * A first-class function that maps another function across an iterable in parallel. + * + * @return A function that maps another function across an iterable in parallel. + */ + public F, F, Promise>>> parMapIterable() { + return curry(new F2, Iterable, Promise>>() { + public Promise> f(final F abf, final Iterable iterable) { + return parMap(iterable, abf); + } + }); + } + + /** + * Maps across an Array in parallel. + * + * @param as An array to map across in parallel. + * @param f A function to map across the given Array. + * @return A Promise of a new Array with the given function applied to each element. + */ + public Promise> parMap(final Array as, final F f) { + return parMap(as.toStream(), f).fmap(new F, Array>() { + public Array f(final Stream stream) { + return stream.toArray(); + } + }); + } + + /** + * A first-class function that maps another function across an array in parallel. + * + * @return A function that maps another function across an array in parallel. + */ + public F, F, Promise>>> parMapArray() { + return curry(new F2, Array, Promise>>() { + public Promise> f(final F abf, final Array array) { + return parMap(array, abf); + } + }); + } + + /** + * Maps a function across a Zipper in parallel. + * + * @param za A Zipper to map across in parallel. + * @param f A function to map across the given Zipper. + * @return A promise of a new Zipper with the given function applied to each element. + */ + public Promise> parMap(final Zipper za, final F f) { + return parMap(za.rights(), f) + .apply(promise(f).f(za.focus()).apply(parMap(za.lefts(), f).fmap(curry(Zipper.zipper())))); + } + + /** + * Maps a function across a Tree in parallel. + * + * @param ta A Tree to map across in parallel. + * @param f A function to map across the given Tree. + * @return A promise of a new Tree with the given function applied to each element. + */ + public Promise> parMap(final Tree ta, final F f) { + return mapM(ta.subForest(), this., Tree>mapStream().f(this.parMapTree().f(f))) + .apply(promise(f).f(ta.root()).fmap(Tree.node())); + } + + /** + * A first-class function that maps across a Tree in parallel. + * + * @return A function that maps a given function across a Tree in parallel. + */ + public F, F, Promise>>> parMapTree() { + return curry(new F2, Tree, Promise>>() { + public Promise> f(final F abf, final Tree tree) { + return parMap(tree, abf); + } + }); + } + + /** + * Maps a function across a TreeZipper in parallel. + * + * @param za A TreeZipper to map across in parallel. + * @param f A function to map across the given TreeZipper. + * @return A promise of a new TreeZipper with the given function applied to each element of the tree. + */ + public Promise> parMap(final TreeZipper za, final F f) { + final F, Tree> tf = Tree.fmap_().f(f); + final P4, Stream>, Stream>, Stream>, A, Stream>>>> p = za.p(); + return mapM(p._4(), + new F>, A, Stream>>, Promise>, B, Stream>>>>() { + public Promise>, B, Stream>>> f( + final P3>, A, Stream>> p3) { + return parMap(p3._3(), tf).apply(promise(f).f(p3._2()).apply( + parMap(p3._1(), tf).fmap(P.>, B, Stream>>p3()))); + } + }).apply(parMap(za.rights(), tf).apply( + parMap(za.lefts(), tf).apply(parMap(p._1(), f).fmap(TreeZipper.treeZipper())))); + } + + /** + * Binds a list-valued function across a list in parallel, concatenating the results into a new list. + * + * @param as A list to bind across in parallel. + * @param f A function to bind across the given list in parallel. + * @return A promise of a new List with the given function bound across its elements. + */ + public Promise> parFlatMap(final List as, final F> f) { + return parFoldMap(as, f, Monoid.listMonoid()); + } + + /** + * Binds a Stream-valued function across a Stream in parallel, concatenating the results into a new Stream. + * + * @param as A Stream to bind across in parallel. + * @param f A function to bind across the given Stream in parallel. + * @return A promise of a new Stream with the given function bound across its elements. + */ + public Promise> parFlatMap(final Stream as, final F> f) { + return parFoldMap(as, f, Monoid.streamMonoid()); + } + + /** + * Binds an Array-valued function across an Array in parallel, concatenating the results into a new Array. + * + * @param as An Array to bind across in parallel. + * @param f A function to bind across the given Array in parallel. + * @return A promise of a new Array with the given function bound across its elements. + */ + public Promise> parFlatMap(final Array as, final F> f) { + return parMap(as, f).fmap(Array.join()); + } + + /** + * Binds an Iterable-valued function across an Iterable in parallel, concatenating the results into a new Iterable. + * + * @param as A Iterable to bind across in parallel. + * @param f A function to bind across the given Iterable in parallel. + * @return A promise of a new Iterable with the given function bound across its elements. + */ + public Promise> parFlatMap(final Iterable as, final F> f) { + return parMap(as, f).fmap(IterableW.>join()) + .fmap(Function., Iterable>vary(Function.>identity())); + } + + /** + * Zips two lists together with a given function, in parallel. + * + * @param as A list to zip with another in parallel. + * @param bs A list to zip with another in parallel. + * @param f A function with which to zip two lists in parallel. + * @return A Promise of a new list with the results of applying the given function across the two lists in lockstep. + */ + public Promise> parZipWith(final List as, final List bs, final F> f) { + return sequence(as.>zipWith(bs, promise(uncurryF2(f)))); + } + + /** + * Zips two streams together with a given function, in parallel. + * + * @param as A stream to zip with another in parallel. + * @param bs A stream to zip with another in parallel. + * @param f A function with which to zip two streams in parallel. + * @return A Promise of a new stream with the results of applying the given function across the two streams, stepwise. + */ + public Promise> parZipWith(final Stream as, final Stream bs, final F> f) { + return sequence(as.>zipWith(bs, promise(uncurryF2(f)))); + } + + /** + * Zips two arrays together with a given function, in parallel. + * + * @param as An array to zip with another in parallel. + * @param bs An array to zip with another in parallel. + * @param f A function with which to zip two arrays in parallel. + * @return A Promise of a new array with the results of applying the given function across the two arrays, stepwise. + */ + public Promise> parZipWith(final Array as, final Array bs, final F> f) { + return parZipWith(as.toStream(), bs.toStream(), f).fmap(new F, Array>() { + public Array f(final Stream stream) { + return stream.toArray(); + } + }); + } + + /** + * Zips two iterables together with a given function, in parallel. + * + * @param as An iterable to zip with another in parallel. + * @param bs An iterable to zip with another in parallel. + * @param f A function with which to zip two iterables in parallel. + * @return A Promise of a new iterable with the results of applying the given function across the two iterables, stepwise. + */ + public Promise> parZipWith(final Iterable as, final Iterable bs, final F> f) { + return parZipWith(iterableStream(as), iterableStream(bs), f).fmap( + Function., Iterable>vary(Function.>identity())); + } + + /** + * Maps with the given function across the given stream in parallel, while folding with + * the given monoid. + * + * @param as A stream to map over and reduce. + * @param map The function to map over the given stream. + * @param reduce The monoid with which to sum the results. + * @return A promise of a result of mapping and folding in parallel. + */ + public Promise parFoldMap(final Stream as, final F map, final Monoid reduce) { + return as.isEmpty() ? promise(p(reduce.zero())) : as.map(promise(map)).foldLeft1(liftM2(reduce.sum())); + } + + /** + * Maps with the given function across chunks of the given stream in parallel, while folding with + * the given monoid. The stream is split into chunks according to the given chunking function, + * the given map function is mapped over all chunks simultaneously, but over each chunk sequentially. + * All chunks are summed concurrently and the sums are then summed sequentially. + * + * @param as A stream to chunk, then map over and reduce. + * @param map The function to map over the given stream. + * @param reduce The monoid with which to sum the results. + * @param chunking A function describing how the stream should be split into chunks. Should return the first chunk + * and the rest of the stream. + * @return A promise of a result of mapping and folding in parallel. + */ + public Promise parFoldMap(final Stream as, final F map, final Monoid reduce, + final F, P2, Stream>> chunking) { + return parMap(Stream.unfold(new F, Option, Stream>>>() { + public Option, Stream>> f(final Stream stream) { + return stream.isEmpty() ? Option., Stream>>none() : some(chunking.f(stream)); + } + }, as), Stream.map_().f(map)).bind(new F>, Promise>() { + public Promise f(final Stream> stream) { + return parMap(stream, reduce.sumLeftS()).fmap(reduce.sumLeftS()); + } + }); + } + + /** + * Maps with the given function across chunks of the given Iterable in parallel, while folding with + * the given monoid. The Iterable is split into chunks according to the given chunking function, + * the given map function is mapped over all chunks simultaneously, but over each chunk sequentially. + * All chunks are summed concurrently and the sums are then summed sequentially. + * + * @param as An Iterable to chunk, then map over and reduce. + * @param map The function to map over the given Iterable. + * @param reduce The monoid with which to sum the results. + * @param chunking A function describing how the Iterable should be split into chunks. Should return the first chunk + * and the rest of the Iterable. + * @return A promise of a result of mapping and folding in parallel. + */ + public Promise parFoldMap(final Iterable as, final F map, final Monoid reduce, + final F, P2, Iterable>> chunking) { + return parFoldMap(iterableStream(as), map, reduce, new F, P2, Stream>>() { + public P2, Stream> f(final Stream stream) { + final F, Stream> is = new F, Stream>() { + public Stream f(final Iterable iterable) { + return iterableStream(iterable); + } + }; + return chunking.f(stream).map1(is).map2(is); + } + }); + } + + /** + * Maps with the given function across the given iterable in parallel, while folding with + * the given monoid. + * + * @param as An Iterable to map over and reduce. + * @param map The function to map over the given Iterable. + * @param reduce The Monoid with which to sum the results. + * @return A promise of a result of mapping and folding in parallel. + */ + public Promise parFoldMap(final Iterable as, final F map, final Monoid reduce) { + return parFoldMap(iterableStream(as), map, reduce); + } + + + /** + * Maps the given function across all positions of the given zipper in parallel. + * + * @param za A zipper to extend the given function across. + * @param f A function to extend across the given zipper. + * @return A promise of a new zipper of the results of applying the given function to all positions of the given + * zipper. + */ + public Promise> parExtend(final Zipper za, final F, B> f) { + return parMap(za.positions(), f); + } + + /** + * Maps the given function across all subtrees of the given Tree in parallel. + * + * @param ta A tree to extend the given function across. + * @param f A function to extend across the given Tree. + * @return A promise of a new Tree of the results of applying the given function to all subtrees of the given Tree. + */ + public Promise> parExtend(final Tree ta, final F, B> f) { + return parMap(ta.cojoin(), f); + } + + /** + * Maps the given function across all positions of the given TreeZipper in parallel. + * + * @param za A TreeZipper to extend the given function across. + * @param f A function to extend across the given TreeZipper. + * @return A promise of a new TreeZipper of the results of applying the given function to all positions of the + * given TreeZipper. + */ + public Promise> parExtend(final TreeZipper za, final F, B> f) { + return parMap(za.positions(), f); + } + + /** + * Maps the given function across all sublists of the given NonEmptyList in parallel. + * + * @param as A NonEmptyList to extend the given function across. + * @param f A function to extend across the given NonEmptyList + * @return A promise of a new NonEmptyList of the results of applying the given function to all sublists of the + * given NonEmptyList. + */ + public Promise> parExtend(final NonEmptyList as, final F, B> f) { + return parMap(as.tails(), f); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/control/parallel/Promise.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/control/parallel/Promise.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,445 @@ +package fj.control.parallel; + +import fj.Effect; +import fj.F; +import fj.F2; +import fj.P; +import fj.P1; +import fj.P2; +import fj.Unit; +import static fj.P.p; +import static fj.Function.curry; +import static fj.Function.identity; +import static fj.control.parallel.Actor.actor; +import static fj.control.parallel.Callables.normalise; +import static fj.control.parallel.Actor.queueActor; +import fj.data.Either; +import fj.data.List; +import fj.data.Option; +import static fj.data.Option.none; +import static fj.data.Option.some; +import fj.data.Stream; +import fj.function.Effect1; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Represents a non-blocking future value. Products, functions, and actors, given to the methods on this class, + * are executed concurrently, and the Promise serves as a handle on the result of the computation. Provides monadic + * operations so that future computations can be combined + *

+ * Author: Runar + */ +public final class Promise { + + private final Actor, Actor>, Promise>> actor; + + private final Strategy s; + + private final CountDownLatch l = new CountDownLatch(1); + private volatile Option v = none(); + private final Queue> waiting = new LinkedList>(); + + private Promise(final Strategy s, final Actor, Actor>, Promise>> qa) { + this.s = s; + actor = qa; + } + + private static Promise mkPromise(final Strategy s) { + final Actor, Actor>, Promise>> q = + queueActor(s, new Effect1, Actor>, Promise>>() { + public void f(final P2, Actor>, Promise> p) { + final Promise snd = p._2(); + final Queue> as = snd.waiting; + if (p._1().isLeft()) { + final A a = p._1().left().value()._1(); + snd.v = some(a); + snd.l.countDown(); + while (!as.isEmpty()) + as.remove().act(a); + } else if (snd.v.isNone()) + as.add(p._1().right().value()); + else + p._1().right().value().act(snd.v.some()); + } + }); + return new Promise(s, q); + } + + /** + * Promises to provide the value of the given 1-product, in the future. + * Represents the unit function for promises. + * + * @param s The strategy with which to fulfil the promise. + * @param a The 1-product to evaluate concurrently. + * @return A promise representing the future result of evaluating the given 1-product. + */ + public static Promise promise(final Strategy s, final P1 a) { + final Promise p = mkPromise(s); + p.actor.act(P.p(Either., Actor>left(a), p)); + return p; + } + + /** + * Provides a first-class unit function for promises. + * + * @param s The strategy with which to fulfil promises. + * @return A function that, given a 1-product, yields a promise of that product's value. + */ + public static F, Promise> promise(final Strategy s) { + return new F, Promise>() { + public Promise f(final P1 a) { + return promise(s, a); + } + }; + } + + /** + * Provides a promise to call the given Callable in the future. + * + * @param s The strategy with which to fulfil the promise. + * @param a The Callable to evaluate concurrently. + * @return A promise of a new Callable that will return the result of calling the given Callable. + */ + public static Promise> promise(final Strategy s, final Callable a) { + return promise(s, new P1>() { + public Callable _1() { + return normalise(a); + } + }); + } + + /** + * Transforms any function so that it returns a promise of a value instead of an actual value. + * Represents the Kleisli arrow for the Promise monad. + * + * @param s The strategy with which to fulfil the promise. + * @param f The function to turn into a promise-valued function. + * @return The given function transformed into a function that returns a promise. + */ + public static F> promise(final Strategy s, final F f) { + return new F>() { + public Promise f(final A a) { + return promise(s, P1.curry(f).f(a)); + } + }; + } + + /** + * Promises to send a value to the given actor in the future. + * + * @param a An actor that will receive this Promise's value in the future. + */ + public void to(final Actor a) { + actor.act(P.p(Either., Actor>right(a), this)); + } + + /** + * Provides a promise to apply the given function to this promise's future value (covariant functor pattern). + * + * @param f The function to apply to this promise's future value. + * @return A promise representing the future result of applying the given function to this promised value. + */ + public Promise fmap(final F f) { + return bind(promise(s, f)); + } + + /** + * Promotes any function to a transformation between promises (covariant functor pattern). + * + * @param f The function to promote to a transformation between promises. + * @return That function lifted to a function on Promises. + */ + public static F, Promise> fmap_(final F f) { + return new F, Promise>() { + public Promise f(final Promise a) { + return a.fmap(f); + } + }; + } + + /** + * Turns a promise of a promise into just a promise. The join function for the Promise monad. + * Promise to give it a Promise of an A, and it will promise you an A in return. + * + * @param p A promise of a promise. + * @return The promised promise. + */ + public static Promise join(final Promise> p) { + final F, Promise> id = identity(); + return p.bind(id); + } + + /** + * Turns a product of a promise into just a promise. Does not block on the product by calling it, + * but creates a new promise with a final join. + * + * @param s The strategy with which to fulfil the promise. + * @param p A product-1 of a promise to turn into just a promise. + * @return The joined promise. + */ + public static Promise join(final Strategy s, final P1> p) { + return join(promise(s, p)); + } + + /** + * Binds the given function over this promise, with a final join. + * The bind function for the Promise monad. + * + * @param f The function to bind over this promise. + * @return The result of applying the given function to this promised value. + */ + public Promise bind(final F> f) { + final Promise r = mkPromise(s); + final Actor ab = actor(s, new Effect1() { + public void f(final B b) { + r.actor.act(P.p(Either., Actor>left(P.p(b)), r)); + } + }); + to(ab.promise().comap(f)); + return r; + } + + /** + * Performs function application within a promise (applicative functor pattern). + * + * @param pf The promised function to apply. + * @return A new promise after applying the given promised function to this promise. + */ + public Promise apply(final Promise> pf) { + return pf.bind(new F, Promise>() { + public Promise f(final F f) { + return fmap(f); + } + }); + } + + /** + * Binds the given function to this promise and the given promise, with a final join. + * + * @param pb A promise with which to bind the given function. + * @param f The function to apply to the given promised values. + * @return A new promise after performing the map, then final join. + */ + public Promise bind(final Promise pb, final F> f) { + return pb.apply(fmap(f)); + } + + /** + * Binds the given function to this promise and the given promise, with a final join. + * + * @param p A promise with which to bind the given function. + * @param f The function to apply to the given promised values. + * @return A new promise after performing the map, then final join. + */ + public Promise bind(final P1> p, final F> f) { + return join(s, p).apply(fmap(f)); + } + + /** + * Promotes a function of arity-2 to a function on promises. + * + * @param f The function to promote. + * @return A function of arity-2 promoted to map over promises. + */ + public static F, F, Promise>> liftM2(final F> f) { + return curry(new F2, Promise, Promise>() { + public Promise f(final Promise ca, final Promise cb) { + return ca.bind(cb, f); + } + }); + } + + /** + * Turns a List of promises into a single promise of a List. + * + * @param s The strategy with which to sequence the promises. + * @param as The list of promises to transform. + * @return A single promise for the given List. + */ + public static Promise> sequence(final Strategy s, final List> as) { + return join(foldRight(s, liftM2(List.cons()), promise(s, P.p(List.nil()))).f(as)); + } + + /** + * First-class version of the sequence function through a List. + * + * @param s The strategy with which to sequence a given list of promises. + * @return A function that turns a list of promises into a single promise of a list. + */ + public static F>, Promise>> sequence(final Strategy s) { + return new F>, Promise>>() { + public Promise> f(final List> as) { + return sequence(s, as); + } + }; + } + + /** + * Turns a Stream of promises into a single promise of a Stream. + * + * @param s The strategy with which to sequence the promises. + * @param as The Stream of promises to transform. + * @return A single promise for the given Stream. + */ + public static Promise> sequence(final Strategy s, final Stream> as) { + return join(foldRightS(s, curry(new F2, P1>>, Promise>>() { + public Promise> f(final Promise o, final P1>> p) { + return o.bind(new F>>() { + public Promise> f(final A a) { + return p._1().fmap(Stream.cons_().f(a)); + } + }); + } + }), promise(s, P.p(Stream.nil()))).f(as)); + } + + /** + * First-class version of the sequence function through a Stream. + * + * @param s The strategy with which to sequence a given Stream of promises. + * @return A function that turns a list of promises into a single promise of a Stream.. + */ + public static F>, Promise>> sequenceS(final Strategy s) { + return new F>, Promise>>() { + public Promise> f(final List> as) { + return sequence(s, as); + } + }; + } + + /** + * Transforms a product of a promise to a promise of a product. + * + * @param s The strategy with which to traverse the promise. + * @param p A product of a promise to traverse. + * @return A promised product. + */ + public static Promise> sequence(final Strategy s, final P1> p) { + return join(promise(s, p)).fmap(P.p1()); + } + + /** + * Performs a right-fold reduction across a list in constant stack space. + * + * @param s The strategy with which to fold the list. + * @param f The function to apply on each element of the list. + * @param b The beginning value to start the application from. + * @return The final result after the right-fold reduction. + */ + public static F, Promise> foldRight(final Strategy s, final F> f, final B b) { + return new F, Promise>() { + public Promise f(final List as) { + return as.isEmpty() ? promise(s, p(b)) : liftM2(f).f(promise(s, P.p(as.head()))).f( + join(s, P1.curry(this).f(as.tail()))); + } + }; + } + + /** + * Performs a right-fold reduction across a Stream in constant stack space. + * + * @param s The strategy with which to fold the Stream. + * @param f The function to apply on each element of the Stream. + * @param b The beginning value to start the application from. + * @return The final result after the right-fold reduction. + */ + public static F, Promise> foldRightS(final Strategy s, final F, B>> f, + final B b) { + return new F, Promise>() { + public Promise f(final Stream as) { + return as.isEmpty() ? promise(s, P.p(b)) : liftM2(f).f(promise(s, P.p(as.head()))).f( + Promise.>join(s, new P1>>() { + public Promise> _1() { + return f(as.tail()._1()).fmap(P.p1()); + } + })); + } + }; + } + + /** + * Waits if necessary for the computation to complete, and then retrieves its result. + * + * @return The promised value. + */ + public A claim() { + try { + l.await(); + } catch (InterruptedException e) { + throw new Error(e); + } + return v.some(); + } + + /** + * Waits if necessary for the computation to complete, and then retrieves its result. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return The promised value, or none if the timeout was reached. + */ + public Option claim(final long timeout, final TimeUnit unit) { + try { + if (l.await(timeout, unit)) + return v; + } catch (InterruptedException e) { + throw new Error(e); + } + return none(); + } + + /** + * Returns true if this promise has been fulfilled. + * + * @return true if this promise has been fulfilled. + */ + public boolean isFulfilled() { + return v.isSome(); + } + + /** + * Binds the given function across a promise of this promise (Comonad pattern). + * + * @param f A function to apply within a new promise of this promise. + * @return A new promise of the result of applying the given function to this promise. + */ + public Promise cobind(final F, B> f) { + return promise(s, new P1() { + public B _1() { + return f.f(Promise.this); + } + }); + } + + /** + * Duplicates this promise to a promise of itself (Comonad pattern). + * + * @return a promise of this promise. + */ + public Promise> cojoin() { + final F, Promise> id = identity(); + return cobind(id); + } + + /** + * Applies a stream of comonadic functions to this promise, returning a stream of values. + * + * @param fs A stream of functions to apply to this promise. + * @return A stream of the results of applying the given stream of functions to this promise. + */ + public Stream sequenceW(final Stream, B>> fs) { + return fs.isEmpty() + ? Stream.nil() + : Stream.cons(fs.head().f(this), new P1>() { + public Stream _1() { + return sequenceW(fs.tail()._1()); + } + }); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/control/parallel/Strategy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/control/parallel/Strategy.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,553 @@ +package fj.control.parallel; + +import fj.Effect; +import fj.F; +import fj.F2; +import fj.Function; +import fj.P; +import fj.P1; +import static fj.Function.compose; +import static fj.Function.curry; +import fj.data.Java; +import fj.data.List; +import fj.data.Array; +import fj.function.Effect1; + +import java.util.concurrent.Callable; +import java.util.concurrent.CompletionService; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; + +/** + * Functional-style parallel evaluation strategies. + * A Strategy is a method of evaluating a product-1, yielding another product-1 from which the result of its evaluation + * can be retrieved at a later time. + *

+ * + * @version %build.number% + */ +public final class Strategy { + + private final F, P1> f; + + private Strategy(final F, P1> f) { + this.f = f; + } + + /** + * Returns the functional representation of this Strategy, a function that evaluates a product-1. + * + * @return The function representing this strategy, which evaluates a product-1. + */ + public F, P1> f() { + return f; + } + + /** + * Constructs a strategy from the given evaluation function. + * + * @param f The execution function for the strategy + * @return A strategy that uses the given function to evaluate product-1s. + */ + public static Strategy strategy(final F, P1> f) { + return new Strategy(f); + } + + /** + * Apply the strategy to the given product-1. + * + * @param a A P1 to evaluate according to this strategy. + * @return A P1 that yields the value from calling the given product-1. + */ + public P1 par(final P1 a) { + return f().f(a); + } + + /** + * Promotes a function to a concurrent function. + * + * @param f A function to promote to a concurrent function. + * @return A function that executes concurrently when called, yielding a Future value. + */ + public F> concurry(final F f) { + return compose(f(), P1.curry(f)); + } + + /** + * Promotes a function of arity-2 to a concurrent function. + * + * @param f The function to promote to a concurrent function. + * @return A function that executes concurrently when called, yielding a product-1 that returns the value. + */ + public F>> concurry(final F2 f) { + return new F>>() { + public F> f(final B b) { + return concurry(curry(f).f(b)); + } + }; + } + + /** + * Waits for every Future in a list to obtain a value, and collects those values in a list. + * + * @param xs The list of Futures from which to get values. + * @return A list of values extracted from the Futures in the argument list. + */ + public static List> mergeAll(final List> xs) { + return xs.map(Strategy.obtain()); + } + + /** + * Evaluates a list of product-1s in parallel. + * + * @param ps A list to evaluate in parallel. + * @return A list of the values of the product-1s in the argument. + */ + public P1> parList(final List> ps) { + return P1.sequence(ps.map(f())); + } + + /** + * Maps the given function over the given list in parallel using this strategy. + * + * @param f A function to map over the given list in parallel. + * @param bs A list over which to map the given function in parallel. + * @return A product-1 that returns the list with all of its elements transformed by the given function. + */ + public P1> parMap(final F f, final List bs) { + return P1.sequence(bs.map(concurry(f))); + } + + /** + * Maps the given function over the given array in parallel using this strategy. + * + * @param f A function to map over the given array in parallel. + * @param bs An array over which to map the given function in parallel. + * @return A product-1 that returns the array with all of its elements transformed by the given function. + */ + public P1> parMap(final F f, final Array bs) { + return P1.sequence(bs.map(concurry(f))); + } + + /** + * A strict version of parMap over lists. + * Maps the given function over the given list in parallel using this strategy, + * blocking the current thread until all values have been obtained. + * + * @param f A function to map over the given list in parallel. + * @param bs A list over which to map the given function in parallel. + * @return A list with all of its elements transformed by the given function. + */ + public List parMap1(final F f, final List bs) { + return compose(P1.>__1(), parMapList(f)).f(bs); + } + + /** + * A strict version of parMap over arrays. + * Maps the given function over the given arrays in parallel using this strategy, + * blocking the current thread until all values have been obtained. + * + * @param f A function to map over the given array in parallel. + * @param bs An array over which to map the given function in parallel. + * @return An array with all of its elements transformed by the given function. + */ + public Array parMap1(final F f, final Array bs) { + return compose(P1.>__1(), parMapArray(f)).f(bs); + } + + /** + * Promotes a function to a parallel function on lists using this strategy. + * + * @param f A function to transform into a parallel function on lists. + * @return The function transformed into a parallel function on lists. + */ + public F, P1>> parMapList(final F f) { + return new F, P1>>() { + public P1> f(final List as) { + return parMap(f, as); + } + }; + } + + /** + * First-class version of parMap on lists. + * + * @return A function that promotes another function to a parallel function on lists. + */ + public F, F, P1>>> parMapList() { + return new F, F, P1>>>() { + public F, P1>> f(final F f) { + return parMapList(f); + } + }; + } + + /** + * First-class version of parMap1 on lists (parallel list functor). + * + * @return A function that promotes another function to a blocking parallel function on lists. + */ + public F, F, List>> parMapList1() { + return new F, F, List>>() { + public F, List> f(final F f) { + return new F, List>() { + public List f(final List bs) { + return parMap1(f, bs); + } + }; + } + }; + } + + /** + * Promotes a function to a parallel function on arrays using this strategy. + * + * @param f A function to transform into a parallel function on arrays. + * @return The function transformed into a parallel function on arrays. + */ + public F, P1>> parMapArray(final F f) { + return new F, P1>>() { + public P1> f(final Array as) { + return parMap(f, as); + } + }; + } + + /** + * First-class version of parMap on arrays. + * + * @return A function that promotes another function to a parallel function on arrays. + */ + public F, F, P1>>> parMapArray() { + return new F, F, P1>>>() { + public F, P1>> f(final F f) { + return parMapArray(f); + } + }; + } + + /** + * First-class version of parMap1 on arrays (parallel array functor). + * + * @return A function that promotes another function to a blocking parallel function on arrays. + */ + public F, F, Array>> parMapArray1() { + return new F, F, Array>>() { + public F, Array> f(final F f) { + return new F, Array>() { + public Array f(final Array bs) { + return parMap1(f, bs); + } + }; + } + }; + } + + /** + * Binds the given function in parallel across the given list, using the given strategy, with a final join. + * + * @param s The strategy to use for parallelization. + * @param f The function to bind across the given list. + * @param as The list across which to bind the given function. + * @return A P1 containing the result of the parallel map operation after the final join. + */ + public static P1> parFlatMap(final Strategy> s, + final F> f, + final List as) { + return P1.fmap(List.join()).f(s.parMap(f, as)); + } + + /** + * Binds the given function in parallel across the given array, using the given strategy, with a final join. + * + * @param s The strategy to use for parallelization. + * @param f The function to bind across the given array. + * @param as The array across which to bind the given function. + * @return A P1 containing the result of the parallel map operation after the final join. + */ + public static P1> parFlatMap(final Strategy> s, + final F> f, + final Array as) { + return P1.fmap(Array.join()).f(s.parMap(f, as)); + } + + /** + * Sequentially evaluates chunks (sub-sequences) of a list in parallel. Splits the list into chunks, + * evaluating the chunks simultaneously, but each chunk as a sequence. + * + * @param s The strategy to use for parallelization. + * @param chunkLength The length of each sequence. + * @param as The list to evaluate in parallel chunks. + * @return A product-1 containing the list of results extracted from the given list of product-1s. + */ + public static P1> parListChunk(final Strategy> s, + final int chunkLength, + final List> as) { + return P1.fmap(List.join()).f(s.parList(as.partition(chunkLength).map(P1.sequenceList()))); + } + + /** + * Zips together two lists in parallel using a given function, with this strategy. + * Calls the given function once for each corresponding pair in the lists, position-wise, + * passing elements from the first list to the first argument of the function, and elements from the second list + * to the second argument of the function, yielding a list of the results. + * If the lists are not of the same length, the remaining elements of the longer list are ignored. + * + * @param f The function of arity-2 with which to zip. + * @param bs A list to zip with the given function. + * @param cs A list to zip with the given function. + * @return The list of the results of calling the given function on corresponding elements of the given lists. + */ + public P1> parZipWith(final F2 f, final List bs, final List cs) { + return P1.sequence(bs.zipWith(cs, concurry(f))); + } + + /** + * Zips together two arrays in parallel using a given function, with this strategy. + * Calls the given function once for each corresponding pair in the arrays, position-wise, + * passing elements from the first array to the first argument of the function, and elements from the second array + * to the second argument of the function, yielding a array of the results. + * If the arrays are not of the same length, the remaining elements of the longer array are ignored. + * + * @param f The function of arity-2 with which to zip. + * @param bs A array to zip with the given function. + * @param cs A array to zip with the given function. + * @return The array of the results of calling the given function on corresponding elements of the given arrays. + */ + public P1> parZipWith(final F2 f, final Array bs, final Array cs) { + return P1.sequence(bs.zipWith(cs, concurry(f))); + } + + /** + * Lifts a given function of arity-2 so that it zips together two lists in parallel, + * using this strategy, calling the function once for each corresponding pair in the lists, position-wise. + * + * @param f The function of arity-2 with which to zip. + * @return A transformation that zips two lists using the argument function, in parallel. + */ + public F2, List, P1>> parZipListWith(final F2 f) { + return new F2, List, P1>>() { + public P1> f(final List bs, final List cs) { + return parZipWith(f, bs, cs); + } + }; + } + + /** + * Lifts a given function of arity-2 so that it zips together two arrays in parallel, + * using this strategy, calling the function once for each corresponding pair in the arrays, position-wise. + * + * @param f The function of arity-2 with which to zip. + * @return A transformation that zips two arrays using the argument function, in parallel. + */ + public F2, Array, P1>> parZipArrayWith(final F2 f) { + return new F2, Array, P1>>() { + public P1> f(final Array bs, final Array cs) { + return parZipWith(f, bs, cs); + } + }; + } + + /** + * Returns a function which returns a product-1 which waits for the given Future to obtain a value. + * + * @return A function which, given a Future, yields a product-1 that waits for it. + */ + public static F, P1> obtain() { + return new F, P1>() { + public P1 f(final Future t) { + return obtain(t); + } + }; + } + + /** + * Provides a product-1 that waits for the given future to obtain a value. + * + * @param t A Future for which to wait. + * @return A product-1 that waits for the given future to obtain a value. + */ + public static P1 obtain(final Future t) { + return new P1() { + public A _1() { + try { + return t.get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new Error(e); + } catch (ExecutionException e) { + throw new Error(e); + } + } + }; + } + + /** + * Returns an Effect that waits for a given Future to obtain a value, discarding the value. + * + * @return An effect, which, given a Future, waits for it to obtain a value, discarding the value. + */ + public static Effect1> discard() { + return new Effect1>() { + public void f(final Future a) { + Strategy.obtain().f(a)._1(); + } + }; + } + + /** + * Provides a simple parallelization strategy that creates, and discards, a new thread for + * every evaluation. + * + * @return a simple parallelization strategy that creates, and discards, a new thread for + * every evaluation. + */ + public static Strategy simpleThreadStrategy() { + return strategy(new F, P1>() { + public P1 f(final P1 p) { + final FutureTask t = new FutureTask(Java.P1_Callable().f(p)); + new Thread(t).start(); + return obtain(t); + } + }); + } + + /** + * Provides a parallelization strategy that uses an ExecutorService to control the method and + * degree of parallelism. + * + * @param s The ExecutorService to use for scheduling evaluations. + * @return A Strategy that uses the provided ExecutorService to control the method and degree + * of parallelism. + */ + public static Strategy executorStrategy(final ExecutorService s) { + return strategy(new F, P1>() { + public P1 f(final P1 p) { + return obtain(s.submit(Java.P1_Callable().f(p))); + } + }); + } + + /** + * Provides a parallelization strategy that uses a CompletionService to control the method and + * degree of parallelism, and where each parallel task's completion is registered with the service. + * + * @param s The CompletionService to use for scheduling evaluations and detect their completion. + * @return A Strategy that uses the provided CompletionService to control the method and degree of parallelism, + * and notifies the service of task completion. + */ + public static Strategy completionStrategy(final CompletionService s) { + return strategy(new F, P1>() { + public P1 f(final P1 p) { + return obtain(s.submit(Java.P1_Callable().f(p))); + } + }); + } + + /** + * Provides a strategy that performs sequential (non-concurrent) evaluation of its argument. + * + * @return A strategy that performs sequential (non-concurrent) evaluation of its argument. + */ + public static Strategy seqStrategy() { + return strategy(new F, P1>() { + public P1 f(final P1 a) { + return P.p(a._1()); + } + }); + } + + /** + * Provides a strategy that performs no evaluation of its argument. + * + * @return A strategy that performs no evaluation of its argument. + */ + public static Strategy idStrategy() { + return strategy(Function.>identity()); + } + + /** + * Maps the given bijective transformation across this strategy (Exponential Functor pattern). + * + * @param f A transformation from this strategy's codomain to the resulting strategy's codomain. + * @param g A transformation from the resulting strategy's domain to this strategy's domain. + * @return A new strategy that maps to this strategy and back again. + */ + public Strategy xmap(final F, P1> f, final F, P1> g) { + return strategy(compose(f, compose(f(), g))); + } + + /** + * Maps the given transformation across this strategy's domain (Invariant Functor pattern). + * + * @param f A transformation from this strategy's codomain to the resulting strategy's codomain. + * @return A new strategy that applies the given transformation after each application of this strategy. + */ + public Strategy map(final F, P1> f) { + return xmap(f, Function.>identity()); + } + + /** + * Maps the given transformation across this strategy's codomain (Invariant Functor pattern). + * + * @param f A transformation from the resulting strategy's domain to this strategy's domain. + * @return A new strategy that applies the given transformation before each application of this strategy. + */ + public Strategy comap(final F, P1> f) { + return xmap(Function.>identity(), f); + } + + /** + * Provides an error-handling strategy. Captures any uncaught runtime errors encountered by this strategy and applies + * the given side-effect to them. + * + * @param e The effect that should handle errors. + * @return A strategy that captures any runtime errors with a side-effect. + */ + public Strategy errorStrategy(final Effect1 e) { + return errorStrategy(this, e); + } + + /** + * Provides an error-handling strategy. Captures any uncaught runtime errors encountered by the given strategy + * and applies the given side-effect to them. + * + * @param s The strategy to equip with an error-handling effect. + * @param e The effect that should handle errors. + * @return A strategy that captures any runtime errors with a side-effect. + */ + public static Strategy errorStrategy(final Strategy s, final Effect1 e) { + return s.comap(new F, P1>() { + public P1 f(final P1 a) { + return new P1() { + public A _1() { + try { + return a._1(); + } catch (Throwable t) { + final Error error = new Error(t); + e.f(error); + throw error; + } + } + }; + } + }); + } + + /** + * Provides a normalising strategy that fully evaluates its Callable argument. + * + * @param s A non-normalising strategy to use for the evaluation. + * @return A new strategy that fully evaluates Callables, using the given strategy. + */ + public static Strategy> callableStrategy(final Strategy> s) { + return s.comap(new F>, P1>>() { + public P1> f(final P1> a) { + return P1.curry(Callables.normalise()).f(a._1()); + } + }); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/control/parallel/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/control/parallel/package-info.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,4 @@ +/** + * Parallelization strategies. + */ +package fj.control.parallel; diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/$.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/$.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,38 @@ +package fj.data; + +import fj.P1; + +/** + * The constant arrow, for attaching a new name to an existing type. For every pair of types A and B, this type + * is the identity morphism from B to B. + */ +@SuppressWarnings({"UnusedDeclaration"}) +public final class $ extends P1 { + + private final B b; + + private $(final B b) { + this.b = b; + } + + /** + * @deprecated JDK 8 warns '_' may not be supported after SE 8. Replaced by {@link #constant} and synonym {@link #__} (prefer constant). + */ + @Deprecated + public static $ _(final B b) { + return constant(b); + } + + public static $ __(final B b) { + return constant(b); + } + + public static $ constant(final B b) { + return new $(b); + } + + + public B _1() { + return b; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Array.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Array.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,1070 @@ +package fj.data; + +import fj.Effect; +import fj.F; +import fj.F2; +import fj.P; +import fj.P1; +import fj.P2; +import fj.Unit; +import fj.function.Effect1; + +import static fj.Function.*; +import static fj.P.p; +import static fj.P.p2; +import static fj.Unit.unit; +import static fj.data.List.iterableList; +import static fj.data.Option.none; +import static fj.data.Option.some; + +import static java.lang.Math.min; +import static java.lang.System.arraycopy; + +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Provides an interface to arrays. + * + * @version %build.number% + */ +public final class Array implements Iterable { + private final Object[] a; + + private Array(final Object[] a) { + this.a = a; + } + + /** + * Returns an iterator for this array. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this array. + */ + public Iterator iterator() { + return toCollection().iterator(); + } + + /** + * Returns the element at the given index if it exists, fails otherwise. + * + * @param index The index at which to get the element to return. + * @return The element at the given index if it exists, fails otherwise. + */ + @SuppressWarnings("unchecked") + public A get(final int index) { + return (A) a[index]; + } + + /** + * Sets the element at the given index to the given value. + * + * @param index The index at which to set the given value. + * @param a The value to set at the given index. + * @return The unit value. + */ + public Unit set(final int index, final A a) { + this.a[index] = a; + return unit(); + } + + /** + * Returns the length of this array. + * + * @return The length of this array. + */ + public int length() { + return a.length; + } + + public ImmutableProjection immutable() { + return new ImmutableProjection(this); + } + + /** + * Returns true is this array is empty, false otherwise. + * + * @return true is this array is empty, false otherwise. + */ + public boolean isEmpty() { + return a.length == 0; + } + + /** + * Returns false is this array is empty, true otherwise. + * + * @return false is this array is empty, true otherwise. + */ + public boolean isNotEmpty() { + return a.length != 0; + } + + /** + * Returns a copy of the underlying primitive array. + * + * @param c A class for the returned array. + * @return A copy of the underlying primitive array. + */ + public A[] array(final Class c) { + return copyOf(a, a.length, c); + } + + /** + * Returns a copy of the underlying primitive array. + * + * @return A copy of the underlying primitive array; + */ + public Object[] array() { + return copyOf(a, a.length); + } + + /** + * Returns an option projection of this array; None if empty, or the first element in + * Some. + * + * @return An option projection of this array. + */ + @SuppressWarnings("unchecked") + public Option toOption() { + return a.length == 0 ? Option.none() : some((A) a[0]); + } + + /** + * Returns an either projection of this array; the given argument in Left if empty, + * or the first element in Right. + * + * @param x The value to return in left if this array is empty. + * @return An either projection of this array. + */ + @SuppressWarnings("unchecked") + public Either toEither(final P1 x) { + return a.length == 0 ? Either.left(x._1()) : Either.right((A) a[0]); + } + + /** + * Returns a list projection of this array. + * + * @return A list projection of this array. + */ + @SuppressWarnings("unchecked") + public List toList() { + List x = List.nil(); + + for (int i = a.length - 1; i >= 0; i--) { + x = x.cons((A) a[i]); + } + + return x; + } + + /** + * Returns a stream projection of this array. + * + * @return A stream projection of this array. + */ + @SuppressWarnings("unchecked") + public Stream toStream() { + return Stream.unfold(new F>>() { + public Option> f(final Integer o) { + return a.length > o ? some(p((A) a[o], o + 1)) + : Option.>none(); + } + }, 0); + } + + /** + * Maps the given function across this array. + * + * @param f The function to map across this array. + * @return A new array after the given function has been applied to each element. + */ + @SuppressWarnings({"unchecked"}) + public Array map(final F f) { + final Object[] bs = new Object[a.length]; + + for (int i = 0; i < a.length; i++) { + bs[i] = f.f((A) a[i]); + } + + return new Array(bs); + } + + /** + * Filters elements from this array by returning only elements which produce true + * when the given function is applied to them. + * + * @param f The predicate function to filter on. + * @return A new array whose elements all match the given predicate. + */ + @SuppressWarnings("unchecked") + public Array filter(final F f) { + List x = List.nil(); + + for (int i = a.length - 1; i >= 0; i--) { + if (f.f((A) a[i])) + x = x.cons((A) a[i]); + } + + return x.toArray(); + } + + /** + * Performs a side-effect for each element of this array. + * + * @param f The side-effect to perform for the given element. + * @return The unit value. + */ + @SuppressWarnings("unchecked") + public Unit foreach(final F f) { + for (final Object x : a) { + f.f((A) x); + } + + return unit(); + } + + /** + * Performs a side-effect for each element of this array. + * + * @param f The side-effect to perform for the given element. + */ + @SuppressWarnings("unchecked") + public void foreachDoEffect(final Effect1 f) { + for (final Object x : a) { + f.f((A) x); + } + } + + /** + * Performs a right-fold reduction across this array. This function runs in constant stack space. + * + * @param f The function to apply on each element of the array. + * @param b The beginning value to start the application from. + * @return The final result after the right-fold reduction. + */ + @SuppressWarnings("unchecked") + public B foldRight(final F> f, final B b) { + B x = b; + + for (int i = a.length - 1; i >= 0; i--) + x = f.f((A) a[i]).f(x); + + return x; + } + + /** + * Performs a right-fold reduction across this array. This function runs in constant stack space. + * + * @param f The function to apply on each element of the array. + * @param b The beginning value to start the application from. + * @return The final result after the right-fold reduction. + */ + public B foldRight(final F2 f, final B b) { + return foldRight(curry(f), b); + } + + /** + * Performs a left-fold reduction across this array. This function runs in constant space. + * + * @param f The function to apply on each element of the array. + * @param b The beginning value to start the application from. + * @return The final result after the left-fold reduction. + */ + @SuppressWarnings("unchecked") + public B foldLeft(final F> f, final B b) { + B x = b; + + for (final Object aa : a) + x = f.f(x).f((A) aa); + + return x; + } + + /** + * Performs a left-fold reduction across this array. This function runs in constant space. + * + * @param f The function to apply on each element of the array. + * @param b The beginning value to start the application from. + * @return The final result after the left-fold reduction. + */ + public B foldLeft(final F2 f, final B b) { + return foldLeft(curry(f), b); + } + + /** + * Performs a fold left accummulating and returns an array of the intermediate results. + * This function runs in constant stack space. + * + * @param f The function to apply on each argument pair (initial value/previous result and next array element) + * @param b The beginning value to start the application from. + * @return The array containing all intermediate results of the left-fold reduction. + */ + @SuppressWarnings({"unchecked"}) + public Array scanLeft(final F> f, final B b) { + final Object[] bs = new Object[a.length]; + B x = b; + + for (int i = 0; i < a.length; i++) { + x = f.f(x).f((A) a[i]); + bs[i] = x; + } + + return new Array(bs); + } + + /** + * Performs a left-fold accummulating and returns an array of the intermediate results. + * This function runs in constant stack space. + * + * @param f The function to apply on each argument pair (initial value/previous result and next array element) + * @param b The beginning value to start the application from. + * @return The array containing all intermediate results of the left-fold reduction. + */ + public Array scanLeft(final F2 f, final B b) { + return scanLeft(curry(f), b); + } + + /** + * Performs a left-fold accummulating using first array element as a starting value + * and returns an array of the intermediate results. + * It will fail for empty arrays. + * This function runs in constant stack space. + * + * @param f The function to apply on each argument pair (next array element and first array element/previous result) + * @return The array containing all intermediate results of the left-fold reduction. + */ + @SuppressWarnings({"unchecked"}) + public Array scanLeft1(final F> f) { + final Object[] bs = new Object[a.length]; + A x = get(0); + bs[0] = x; + + for (int i = 1; i < a.length; i++) { + x = f.f(x).f((A) a[i]); + bs[i] = x; + } + + return new Array(bs); + } + + /** + * Performs a left-fold accummulating using first array element as a starting value + * and returns an array of the intermediate results. + * It will fail for empty arrays. + * This function runs in constant stack space. + * + * @param f The function to apply on each argument pair (next array element and first array element/previous result) + * @return The array containing all intermediate results of the left-fold reduction. + */ + public Array scanLeft1(final F2 f) { + return scanLeft1(curry(f)); + } + + /** + * Performs a right-fold accummulating and returns an array of the intermediate results. + * This function runs in constant stack space. + * + * @param f The function to apply on each argument pair (previous array element and initial value/previous result) + * @param b The beginning value to start the application from. + * @return The array containing all intermediate results of the right-fold reduction. + */ + @SuppressWarnings({"unchecked"}) + public Array scanRight(final F>f, final B b) { + final Object[] bs = new Object[a.length]; + B x = b; + + for (int i = a.length - 1; i >= 0; i--) { + x = f.f((A) a[i]).f(x); + bs[i] = x; + } + + return new Array(bs); + } + + /** + * Performs a right-fold accummulating and returns an array of the intermediate results. + * This function runs in constant stack space. + * + * @param f The function to apply on each argument pair (previous array element and initial value/previous result) + * @param b The beginning value to start the application from. + * @return The array containing all intermediate results of the right-fold reduction. + */ + public Array scanRight(final F2 f, final B b) { + return scanRight(curry(f), b); + } + + /** + * Performs a right-fold accummulating using last array element as a starting value + * and returns an array of the intermediate results. + * It will fail for empty arrays. + * This function runs in constant stack space. + * + * @param f The function to apply on each argument pair (previous array element and last array element/previous result) + * @return The array containing all intermediate results of the right-fold reduction. + */ + @SuppressWarnings({"unchecked"}) + public Array scanRight1(final F>f) { + final Object[] bs = new Object[a.length]; + A x = get(length() - 1); + bs[length() - 1] = x; + + for (int i = a.length - 2; i >= 0; i--) { + x = f.f((A) a[i]).f(x); + bs[i] = x; + } + + return new Array(bs); + } + + /** + * Performs a right-fold accummulating using last array element as a starting value + * and returns an array of the intermediate results. + * It will fail for empty arrays. + * This function runs in constant stack space. + * + * @param f The function to apply on each argument pair (previous array element and last array element/previous result) + * @return The array containing all intermediate results of the right-fold reduction. + */ + public Array scanRight1(final F2 f) { + return scanRight1(curry(f)); + } + + /** + * Binds the given function across each element of this array with a final join. + * + * @param f The function to apply to each element of this array. + * @return A new array after performing the map, then final join. + */ + @SuppressWarnings({"unchecked"}) + public Array bind(final F> f) { + List> x = List.nil(); + int len = 0; + + for (int i = a.length - 1; i >= 0; i--) { + final Array bs = f.f((A) a[i]); + len = len + bs.length(); + x = x.cons(bs); + } + + final Object[] bs = new Object[len]; + + x.foreach(new F, Unit>() { + private int i; + + public Unit f(final Array x) { + arraycopy(x.a, 0, bs, i, x.a.length); + i = i + x.a.length; + return unit(); + } + }); + + return new Array(bs); + } + + /** + * Performs a bind across each array element, but ignores the element value each time. + * + * @param bs The array to apply in the final join. + * @return A new array after the final join. + */ + public Array sequence(final Array bs) { + final F> c = constant(bs); + return bind(c); + } + + /** + * Binds the given function across each element of this array and the given array with a final + * join. + * + * @param sb A given array to bind the given function with. + * @param f The function to apply to each element of this array and the given array. + * @return A new array after performing the map, then final join. + */ + public Array bind(final Array sb, final F> f) { + return sb.apply(map(f)); + } + + /** + * Binds the given function across each element of this array and the given array with a final + * join. + * + * @param sb A given array to bind the given function with. + * @param f The function to apply to each element of this array and the given array. + * @return A new array after performing the map, then final join. + */ + public Array bind(final Array sb, final F2 f) { + return bind(sb, curry(f)); + } + + /** + * Performs function application within an array (applicative functor pattern). + * + * @param lf The array of functions to apply. + * @return A new array after applying the given array of functions through this array. + */ + public Array apply(final Array> lf) { + return lf.bind(new F, Array>() { + public Array f(final F f) { + return map(new F() { + public B f(final A a) { + return f.f(a); + } + }); + } + }); + } + + /** + * Reverse this array in constant stack space. + * + * @return A new array that is the reverse of this one. + */ + public Array reverse() { + final Object[] x = new Object[a.length]; + + for (int i = 0; i < a.length; i++) { + x[a.length - 1 - i] = a[i]; + } + + return new Array(x); + } + + /** + * Appends the given array to this array. + * + * @param aas The array to append to this one. + * @return A new array that has appended the given array. + */ + public Array append(final Array aas) { + final Object[] x = new Object[a.length + aas.a.length]; + + arraycopy(a, 0, x, 0, a.length); + arraycopy(aas.a, 0, x, a.length, aas.a.length); + + return new Array(x); + } + + /** + * Returns an empty array. + * + * @return An empty array. + */ + public static Array empty() { + return new Array(new Object[0]); + } + + /** + * Constructs an array from the given elements. + * + * @param a The elements to construct the array with. + * @return A new array of the given elements. + */ + public static Array array(final A... a) { + return new Array(a); + } + + /** + * Unsafe package-private constructor. The elements of the given array must be assignable to the given type. + * + * @param a An array with elements of the given type. + * @return A wrapped array. + */ + static Array mkArray(final Object[] a) { + return new Array(a); + } + + /** + * Constructs a singleton array. + * + * @param a The element to put in the array. + * @return An array with the given single element. + */ + public static Array single(final A a) { + return new Array(new Object[]{a}); + } + + /** + * First-class wrapper function for arrays. + * + * @return A function that wraps a given array. + */ + public static F> wrap() { + return new F>() { + public Array f(final A[] as) { + return array(as); + } + }; + } + + /** + * First-class map function for Arrays. + * + * @return A function that maps a given function across a given array. + */ + public static F, F, Array>> map() { + return curry(new F2, Array, Array>() { + public Array f(final F abf, final Array array) { + return array.map(abf); + } + }); + } + + /** + * Joins the given array of arrays using a bind operation. + * + * @param o The array of arrays to join. + * @return A new array that is the join of the given arrays. + */ + public static Array join(final Array> o) { + final F, Array> id = identity(); + return o.bind(id); + } + + /** + * A first-class version of join + * + * @return A function that joins a array of arrays using a bind operation. + */ + public static F>, Array> join() { + return new F>, Array>() { + public Array f(final Array> as) { + return join(as); + } + }; + } + + /** + * Returns true if the predicate holds for all of the elements of this array, + * false otherwise (true for the empty array). + * + * @param f the predicate function to test on each element of this array. + * @return true if the predicate holds for all of the elements of this array, + * false otherwise. + */ + @SuppressWarnings("unchecked") + public boolean forall(final F f) { + for (final Object x : a) + if (!f.f((A) x)) + return false; + + return true; + } + + /** + * Returns true if the predicate holds for at least one of the elements of this + * array, false otherwise (false for the empty array). + * + * @param f the predicate function to test on the elements of this array. + * @return true if the predicate holds for at least one of the elements of this + * array. + */ + @SuppressWarnings("unchecked") + public boolean exists(final F f) { + for (final Object x : a) + if (f.f((A) x)) + return true; + + return false; + } + + /** + * Finds the first occurrence of an element that matches the given predicate or no value if no + * elements match. + * + * @param f The predicate function to test on elements of this array. + * @return The first occurrence of an element that matches the given predicate or no value if no + * elements match. + */ + @SuppressWarnings("unchecked") + public Option find(final F f) { + for (final Object x : a) + if (f.f((A) x)) + return some((A) x); + + return none(); + } + + /** + * Returns an array of integers from the given from value (inclusive) to the given + * to value (exclusive). + * + * @param from The minimum value for the array (inclusive). + * @param to The maximum value for the array (exclusive). + * @return An array of integers from the given from value (inclusive) to the given + * to value (exclusive). + */ + public static Array range(final int from, final int to) { + if (from >= to) + return empty(); + else { + final Array a = new Array(new Integer[to - from]); + + for (int i = from; i < to; i++) + a.set(i - from, i); + + return a; + } + } + + /** + * Zips this array with the given array using the given function to produce a new array. If this + * array and the given array have different lengths, then the longer array is normalised so this + * function never fails. + * + * @param bs The array to zip this array with. + * @param f The function to zip this array and the given array with. + * @return A new array with a length the same as the shortest of this array and the given array. + */ + public Array zipWith(final Array bs, final F> f) { + final int len = min(a.length, bs.length()); + final Array x = new Array(new Object[len]); + + for (int i = 0; i < len; i++) { + x.set(i, f.f(get(i)).f(bs.get(i))); + } + + return x; + } + + /** + * Zips this array with the given array using the given function to produce a new array. If this + * array and the given array have different lengths, then the longer array is normalised so this + * function never fails. + * + * @param bs The array to zip this array with. + * @param f The function to zip this array and the given array with. + * @return A new array with a length the same as the shortest of this array and the given array. + */ + public Array zipWith(final Array bs, final F2 f) { + return zipWith(bs, curry(f)); + } + + /** + * Zips this array with the given array to produce an array of pairs. If this array and the given + * array have different lengths, then the longer array is normalised so this function never fails. + * + * @param bs The array to zip this array with. + * @return A new array with a length the same as the shortest of this array and the given array. + */ + public Array> zip(final Array bs) { + final F>> __2 = p2(); + return zipWith(bs, __2); + } + + /** + * Zips this array with the index of its element as a pair. + * + * @return A new array with the same length as this array. + */ + public Array> zipIndex() { + return zipWith(range(0, length()), new F>>() { + public F> f(final A a) { + return new F>() { + public P2 f(final Integer i) { + return p(a, i); + } + }; + } + }); + } + + /** + * Projects an immutable collection of this array. + * + * @return An immutable collection of this array. + */ + @SuppressWarnings("unchecked") + public Collection toCollection() { + return new AbstractCollection() { + public Iterator iterator() { + return new Iterator() { + private int i; + + public boolean hasNext() { + return i < a.length; + } + + public A next() { + if (i >= a.length) + throw new NoSuchElementException(); + else { + final A aa = (A) a[i]; + i++; + return aa; + } + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + public int size() { + return a.length; + } + }; + } + + /** + * Takes the given iterable to an array. + * + * @param i The iterable to take to an array. + * @return An array from the given iterable. + */ + public static Array iterableArray(final Iterable i) { + return iterableList(i).toArray(); + } + + /** + * Transforms an array of pairs into an array of first components and an array of second components. + * + * @param xs The array of pairs to transform. + * @return An array of first components and an array of second components. + */ + @SuppressWarnings({"unchecked"}) + public static P2, Array> unzip(final Array> xs) { + final int len = xs.length(); + final Array aa = new Array(new Object[len]); + final Array ab = new Array(new Object[len]); + for (int i = len - 1; i >= 0; i--) { + final P2 p = xs.get(i); + aa.set(i, p._1()); + ab.set(i, p._2()); + } + return P.p(aa, ab); + } + + /** + * Projects an array by providing only operations which do not mutate. + */ + public final class ImmutableProjection implements Iterable { + private final Array a; + + private ImmutableProjection(final Array a) { + this.a = a; + } + + /** + * Returns an iterator for this array. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this array. + */ + public Iterator iterator() { + return a.iterator(); + } + + /** + * Returns the element at the given index if it exists, fails otherwise. + * + * @param index The index at which to get the element to return. + * @return The element at the given index if it exists, fails otherwise. + */ + public A get(final int index) { + return a.get(index); + } + + /** + * Returns the length of this array. + * + * @return The length of this array. + */ + public int length() { + return a.length(); + } + + /** + * Returns true is this array is empty, false otherwise. + * + * @return true is this array is empty, false otherwise. + */ + public boolean isEmpty() { + return a.isEmpty(); + } + + /** + * Returns false is this array is empty, true otherwise. + * + * @return false is this array is empty, true otherwise. + */ + public boolean isNotEmpty() { + return a.isNotEmpty(); + } + + /** + * Returns an option projection of this array; None if empty, or the first element + * in Some. + * + * @return An option projection of this array. + */ + public Option toOption() { + return a.toOption(); + } + + /** + * Returns an either projection of this array; the given argument in Left if empty, + * or the first element in Right. + * + * @param x The value to return in left if this array is empty. + * @return An either projection of this array. + */ + public Either toEither(final P1 x) { + return a.toEither(x); + } + + /** + * Returns a list projection of this array. + * + * @return A list projection of this array. + */ + public List toList() { + return a.toList(); + } + + /** + * Returns a stream projection of this array. + * + * @return A stream projection of this array. + */ + public Stream toStream() { + return a.toStream(); + } + + /** + * Maps the given function across this array. + * + * @param f The function to map across this array. + * @return A new array after the given function has been applied to each element. + */ + public Array map(final F f) { + return a.map(f); + } + + /** + * Filters elements from this array by returning only elements which produce true + * when the given function is applied to them. + * + * @param f The predicate function to filter on. + * @return A new array whose elements all match the given predicate. + */ + public Array filter(final F f) { + return a.filter(f); + } + + /** + * Performs a side-effect for each element of this array. + * + * @param f The side-effect to perform for the given element. + * @return The unit value. + */ + public Unit foreach(final F f) { + return a.foreach(f); + } + + /** + * Performs a right-fold reduction across this array. This function uses O(length) stack space. + * + * @param f The function to apply on each element of the array. + * @param b The beginning value to start the application from. + * @return The final result after the right-fold reduction. + */ + public B foldRight(final F> f, final B b) { + return a.foldRight(f, b); + } + + /** + * Performs a left-fold reduction across this array. This function runs in constant space. + * + * @param f The function to apply on each element of the array. + * @param b The beginning value to start the application from. + * @return The final result after the left-fold reduction. + */ + public B foldLeft(final F> f, final B b) { + return a.foldLeft(f, b); + } + + /** + * Binds the given function across each element of this array with a final join. + * + * @param f The function to apply to each element of this array. + * @return A new array after performing the map, then final join. + */ + public Array bind(final F> f) { + return a.bind(f); + } + + /** + * Performs a bind across each array element, but ignores the element value each time. + * + * @param bs The array to apply in the final join. + * @return A new array after the final join. + */ + public Array sequence(final Array bs) { + return a.sequence(bs); + } + + /** + * Performs function application within an array (applicative functor pattern). + * + * @param lf The array of functions to apply. + * @return A new array after applying the given array of functions through this array. + */ + public Array apply(final Array> lf) { + return a.apply(lf); + } + + /** + * Reverse this array in constant stack space. + * + * @return A new array that is the reverse of this one. + */ + public Array reverse() { + return a.reverse(); + } + + /** + * Appends the given array to this array. + * + * @param aas The array to append to this one. + * @return A new array that has appended the given array. + */ + public Array append(final Array aas) { + return a.append(aas); + } + + /** + * Projects an immutable collection of this array. + * + * @return An immutable collection of this array. + */ + public Collection toCollection() { + return a.toCollection(); + } + } + + @SuppressWarnings({"SuspiciousSystemArraycopy", "unchecked", "ObjectEquality", "RedundantCast"}) + public static T[] copyOf(final U[] a, final int len, final Class newType) { + final T[] copy = (Object)newType == Object[].class + ? (T[]) new Object[len] + : (T[]) java.lang.reflect.Array.newInstance(newType.getComponentType(), len); + System.arraycopy(a, 0, copy, 0, + Math.min(a.length, len)); + return copy; + } + + @SuppressWarnings({"unchecked"}) + public static T[] copyOf(final T[] a, final int len) { + return (T[]) copyOf(a, len, a.getClass()); + } + + public static char[] copyOfRange(final char[] a, final int from, final int to) { + final int len = to - from; + if (len < 0) + throw new IllegalArgumentException(from + " > " + to); + final char[] copy = new char[len]; + System.arraycopy(a, from, copy, 0, + Math.min(a.length - from, len)); + return copy; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Conversions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Conversions.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,912 @@ +package fj.data; + +import fj.F; +import fj.P1; +import fj.Unit; +import fj.function.TryEffect0; +import fj.function.Effect0; +import fj.function.Effect1; + +import fj.Try; +import fj.TryEffect; +import fj.Effect; +import fj.function.Try0; +import fj.function.Try1; + +import java.io.IOException; +import static fj.Unit.unit; +import static fj.data.List.asString; +import static fj.data.List.fromString; + +/** + * Functions that convert between data structure types. + * + * @version %build.number% + */ +public final class Conversions { + private Conversions() { + throw new UnsupportedOperationException(); + } + + // BEGIN List -> + + /** + * A function that converts lists to arrays. + * + * @return A function that converts lists to arrays. + */ + public static F, Array> List_Array() { + return new F, Array>() { + public Array f(final List as) { + return as.toArray(); + } + }; + } + + /** + * A function that converts lists to streams. + * + * @return A function that converts lists to streams. + */ + public static F, Stream> List_Stream() { + return new F, Stream>() { + public Stream f(final List as) { + return as.toStream(); + } + }; + } + + /** + * A function that converts lists to options. + * + * @return A function that converts lists to options. + */ + public static F, Option> List_Option() { + return new F, Option>() { + public Option f(final List as) { + return as.toOption(); + } + }; + } + + /** + * A function that converts lists to eithers. + * + * @return A function that converts lists to eithers. + */ + public static F, F, Either>> List_Either() { + return new F, F, Either>>() { + public F, Either> f(final P1 a) { + return new F, Either>() { + public Either f(final List bs) { + return bs.toEither(a); + } + }; + } + }; + } + + /** + * A function that converts lists to strings. + */ + public static final F, String> List_String = new F, String>() { + public String f(final List cs) { + return asString(cs); + } + }; + + /** + * A function that converts lists to string buffers. + */ + public static final F, StringBuffer> List_StringBuffer = new F, StringBuffer>() { + public StringBuffer f(final List cs) { + return new StringBuffer(asString(cs)); + } + }; + + /** + * A function that converts lists to string builders. + */ + public static final F, StringBuilder> List_StringBuilder = new F, StringBuilder>() { + public StringBuilder f(final List cs) { + return new StringBuilder(asString(cs)); + } + }; + + // END List -> + + // BEGIN Array -> + + /** + * A function that converts arrays to lists. + * + * @return A function that converts arrays to lists. + */ + public static F, List> Array_List() { + return new F, List>() { + public List f(final Array as) { + return as.toList(); + } + }; + } + + /** + * A function that converts arrays to streams. + * + * @return A function that converts arrays to streams. + */ + public static F, Stream> Array_Stream() { + return new F, Stream>() { + public Stream f(final Array as) { + return as.toStream(); + } + }; + } + + /** + * A function that converts arrays to options. + * + * @return A function that converts arrays to options. + */ + public static F, Option> Array_Option() { + return new F, Option>() { + public Option f(final Array as) { + return as.toOption(); + } + }; + } + + /** + * A function that converts arrays to eithers. + * + * @return A function that converts arrays to eithers. + */ + public static F, F, Either>> Array_Either() { + return new F, F, Either>>() { + public F, Either> f(final P1 a) { + return new F, Either>() { + public Either f(final Array bs) { + return bs.toEither(a); + } + }; + } + }; + } + + /** + * A function that converts arrays to strings. + */ + public static final F, String> Array_String = new F, String>() { + public String f(final Array cs) { + final StringBuilder sb = new StringBuilder(); + cs.foreachDoEffect(new Effect1() { + public void f(final Character c) { + sb.append(c); + } + }); + return sb.toString(); + } + }; + + /** + * A function that converts arrays to string buffers. + */ + public static final F, StringBuffer> Array_StringBuffer = new F, StringBuffer>() { + public StringBuffer f(final Array cs) { + final StringBuffer sb = new StringBuffer(); + cs.foreachDoEffect(new Effect1() { + public void f(final Character c) { + sb.append(c); + } + }); + return sb; + } + }; + + /** + * A function that converts arrays to string builders. + */ + public static final F, StringBuilder> Array_StringBuilder = + new F, StringBuilder>() { + public StringBuilder f(final Array cs) { + final StringBuilder sb = new StringBuilder(); + cs.foreachDoEffect((Character c) -> sb.append(c)); + return sb; + } + }; + + // END Array -> + + // BEGIN Stream -> + + /** + * A function that converts streams to lists. + * + * @return A function that converts streams to lists. + */ + public static F, List> Stream_List() { + return new F, List>() { + public List f(final Stream as) { + return as.toList(); + } + }; + } + + /** + * A function that converts streams to arrays. + * + * @return A function that converts streams to arrays. + */ + public static F, Array> Stream_Array() { + return new F, Array>() { + public Array f(final Stream as) { + return as.toArray(); + } + }; + } + + /** + * A function that converts streams to options. + * + * @return A function that converts streams to options. + */ + public static F, Option> Stream_Option() { + return new F, Option>() { + public Option f(final Stream as) { + return as.toOption(); + } + }; + } + + /** + * A function that converts streams to eithers. + * + * @return A function that converts streams to eithers. + */ + public static F, F, Either>> Stream_Either() { + return new F, F, Either>>() { + public F, Either> f(final P1 a) { + return new F, Either>() { + public Either f(final Stream bs) { + return bs.toEither(a); + } + }; + } + }; + } + + /** + * A function that converts streams to strings. + */ + public static final F, String> Stream_String = new F, String>() { + public String f(final Stream cs) { + final StringBuilder sb = new StringBuilder(); + cs.foreachDoEffect((Character c) -> sb.append(c)); + return sb.toString(); + } + }; + + /** + * A function that converts streams to string buffers. + */ + public static final F, StringBuffer> Stream_StringBuffer = + new F, StringBuffer>() { + public StringBuffer f(final Stream cs) { + final StringBuffer sb = new StringBuffer(); + cs.foreachDoEffect((Character c) -> sb.append(c)); + return sb; + } + }; + + /** + * A function that converts streams to string builders. + */ + public static final F, StringBuilder> Stream_StringBuilder = + new F, StringBuilder>() { + public StringBuilder f(final Stream cs) { + final StringBuilder sb = new StringBuilder(); + cs.foreachDoEffect((Character c) -> sb.append(c)); + return sb; + } + }; + + // END Stream -> + + // BEGIN Option -> + + /** + * A function that converts options to lists. + * + * @return A function that converts options to lists. + */ + public static F, List> Option_List() { + return new F, List>() { + public List f(final Option o) { + return o.toList(); + } + }; + } + + /** + * A function that converts options to arrays. + * + * @return A function that converts options to arrays. + */ + public static F, Array> Option_Array() { + return new F, Array>() { + public Array f(final Option o) { + return o.toArray(); + } + }; + } + + /** + * A function that converts options to streams. + * + * @return A function that converts options to streams. + */ + public static F, Stream> Option_Stream() { + return new F, Stream>() { + public Stream f(final Option o) { + return o.toStream(); + } + }; + } + + /** + * A function that converts options to eithers. + * + * @return A function that converts options to eithers. + */ + public static F, F, Either>> Option_Either() { + return new F, F, Either>>() { + public F, Either> f(final P1 a) { + return new F, Either>() { + public Either f(final Option o) { + return o.toEither(a); + } + }; + } + }; + } + + /** + * A function that converts options to strings. + */ + public static final F, String> Option_String = new F, String>() { + public String f(final Option o) { + return asString(o.toList()); + } + }; + + /** + * A function that converts options to string buffers. + */ + public static final F, StringBuffer> Option_StringBuffer = + new F, StringBuffer>() { + public StringBuffer f(final Option o) { + return new StringBuffer(asString(o.toList())); + } + }; + + /** + * A function that converts options to string builders. + */ + public static final F, StringBuilder> Option_StringBuilder = + new F, StringBuilder>() { + public StringBuilder f(final Option o) { + return new StringBuilder(asString(o.toList())); + } + }; + + // END Option -> + + // BEGIN Effect + + public static F> Effect0_P1() { + return e -> Effect0_P1(e); + } + + public static P1 Effect0_P1(Effect0 e) { + return Effect.f(e); + } + + public static F Effect1_F(Effect1 e) { + return Effect.f(e); + } + + public static F, F> Effect1_F() { + return e -> Effect1_F(e); + } + + public static IO Effect_IO(Effect0 e) { + return () ->{ + e.f(); + return Unit.unit(); + }; + } + + public static F> Effect_IO() { + return e -> Effect_IO(e); + } + + public static SafeIO Effect_SafeIO(Effect0 e) { + return () -> { + e.f(); + return unit(); + }; + } + + public static F> Effect_SafeIO() { + return e -> Effect_SafeIO(e); + } + + // END Effect + + // BEGIN Either -> + + /** + * A function that converts eithers to lists. + * + * @return A function that converts eithers to lists. + */ + public static F, List> Either_ListA() { + return new F, List>() { + public List f(final Either e) { + return e.left().toList(); + } + }; + } + + /** + * A function that converts eithers to lists. + * + * @return A function that converts eithers to lists. + */ + public static F, List> Either_ListB() { + return new F, List>() { + public List f(final Either e) { + return e.right().toList(); + } + }; + } + + /** + * A function that converts eithers to arrays. + * + * @return A function that converts eithers to arrays. + */ + public static F, Array> Either_ArrayA() { + return new F, Array>() { + public Array f(final Either e) { + return e.left().toArray(); + } + }; + } + + /** + * A function that converts eithers to arrays. + * + * @return A function that converts eithers to arrays. + */ + public static F, Array> Either_ArrayB() { + return new F, Array>() { + public Array f(final Either e) { + return e.right().toArray(); + } + }; + } + + /** + * A function that converts eithers to streams. + * + * @return A function that converts eithers to streams. + */ + public static F, Stream> Either_StreamA() { + return new F, Stream>() { + public Stream f(final Either e) { + return e.left().toStream(); + } + }; + } + + /** + * A function that converts eithers to streams. + * + * @return A function that converts eithers to streams. + */ + public static F, Stream> Either_StreamB() { + return new F, Stream>() { + public Stream f(final Either e) { + return e.right().toStream(); + } + }; + } + + /** + * A function that converts eithers to options. + * + * @return A function that converts eithers to options. + */ + public static F, Option> Either_OptionA() { + return new F, Option>() { + public Option f(final Either e) { + return e.left().toOption(); + } + }; + } + + /** + * A function that converts eithers to options. + * + * @return A function that converts eithers to options. + */ + public static F, Option> Either_OptionB() { + return new F, Option>() { + public Option f(final Either e) { + return e.right().toOption(); + } + }; + } + + /** + * A function that converts eithers to strings. + * + * @return A function that converts eithers to strings. + */ + public static F, String> Either_StringA() { + return new F, String>() { + public String f(final Either e) { + return asString(e.left().toList()); + } + }; + } + + /** + * A function that converts eithers to strings. + * + * @return A function that converts eithers to strings. + */ + public static F, String> Either_StringB() { + return new F, String>() { + public String f(final Either e) { + return asString(e.right().toList()); + } + }; + } + + /** + * A function that converts eithers to string buffers. + * + * @return A function that converts eithers to string buffers. + */ + public static F, StringBuffer> Either_StringBufferA() { + return new F, StringBuffer>() { + public StringBuffer f(final Either e) { + return new StringBuffer(asString(e.left().toList())); + } + }; + } + + /** + * A function that converts eithers to string buffers. + * + * @return A function that converts eithers to string buffers. + */ + public static F, StringBuffer> Either_StringBufferB() { + return new F, StringBuffer>() { + public StringBuffer f(final Either e) { + return new StringBuffer(asString(e.right().toList())); + } + }; + } + + /** + * A function that converts eithers to string builders. + * + * @return A function that converts eithers to string builders. + */ + public static F, StringBuilder> Either_StringBuilderA() { + return new F, StringBuilder>() { + public StringBuilder f(final Either e) { + return new StringBuilder(asString(e.left().toList())); + } + }; + } + + /** + * A function that converts eithers to string builders. + * + * @return A function that converts eithers to string builders. + */ + public static F, StringBuilder> Either_StringBuilderB() { + return new F, StringBuilder>() { + public StringBuilder f(final Either e) { + return new StringBuilder(asString(e.right().toList())); + } + }; + } + + // END Either -> + + // BEGIN F + + public static SafeIO F_SafeIO(F f) { + return () -> f.f(unit()); + } + + public static F, SafeIO> F_SafeIO() { + return f -> F_SafeIO(f); + } + + // END F + + // BEGIN String -> + + /** + * A function that converts strings to lists. + */ + public static final F> String_List = new F>() { + public List f(final String s) { + return fromString(s); + } + }; + + /** + * A function that converts strings to arrays. + */ + public static final F> String_Array = new F>() { + public Array f(final String s) { + return fromString(s).toArray(); + } + }; + + /** + * A function that converts strings to options. + */ + public static final F> String_Option = new F>() { + public Option f(final String s) { + return fromString(s).toOption(); + } + }; + + /** + * A function that converts string to eithers. + * + * @return A function that converts string to eithers. + */ + public static F, F>> String_Either() { + return new F, F>>() { + public F> f(final P1 a) { + return new F>() { + public Either f(final String s) { + return fromString(s).toEither(a); + } + }; + } + }; + } + + /** + * A function that converts strings to streams. + */ + public static final F> String_Stream = new F>() { + public Stream f(final String s) { + return fromString(s).toStream(); + } + }; + + /** + * A function that converts strings to string buffers. + */ + public static final F String_StringBuffer = new F() { + public StringBuffer f(final String s) { + return new StringBuffer(s); + } + }; + + /** + * A function that converts strings to string builders. + */ + public static final F String_StringBuilder = new F() { + public StringBuilder f(final String s) { + return new StringBuilder(s); + } + }; + + // END String -> + + // BEGIN StringBuffer -> + + /** + * A function that converts string buffers to lists. + */ + public static final F> StringBuffer_List = new F>() { + public List f(final StringBuffer s) { + return fromString(s.toString()); + } + }; + + /** + * A function that converts string buffers to arrays. + */ + public static final F> StringBuffer_Array = new F>() { + public Array f(final StringBuffer s) { + return fromString(s.toString()).toArray(); + } + }; + + /** + * A function that converts string buffers to streams. + */ + public static final F> StringBuffer_Stream = + new F>() { + public Stream f(final StringBuffer s) { + return fromString(s.toString()).toStream(); + } + }; + + /** + * A function that converts string buffers to options. + */ + public static final F> StringBuffer_Option = + new F>() { + public Option f(final StringBuffer s) { + return fromString(s.toString()).toOption(); + } + }; + + /** + * A function that converts string buffers to eithers. + * + * @return A function that converts string buffers to eithers. + */ + public static F, F>> StringBuffer_Either() { + return new F, F>>() { + public F> f(final P1 a) { + return new F>() { + public Either f(final StringBuffer s) { + return fromString(s.toString()).toEither(a); + } + }; + } + }; + } + + /** + * A function that converts string buffers to strings. + */ + public static final F StringBuffer_String = new F() { + public String f(final StringBuffer s) { + return s.toString(); + } + }; + + /** + * A function that converts string buffers to string builders. + */ + public static final F StringBuffer_StringBuilder = new F() { + public StringBuilder f(final StringBuffer s) { + return new StringBuilder(s); + } + }; + + // END StringBuffer -> + + // BEGIN StringBuilder -> + + /** + * A function that converts string builders to lists. + */ + public static final F> StringBuilder_List = new F>() { + public List f(final StringBuilder s) { + return fromString(s.toString()); + } + }; + + /** + * A function that converts string builders to arrays. + */ + public static final F> StringBuilder_Array = + new F>() { + public Array f(final StringBuilder s) { + return fromString(s.toString()).toArray(); + } + }; + + /** + * A function that converts string builders to streams. + */ + public static final F> StringBuilder_Stream = + new F>() { + public Stream f(final StringBuilder s) { + return fromString(s.toString()).toStream(); + } + }; + + /** + * A function that converts string builders to options. + */ + public static final F> StringBuilder_Option = + new F>() { + public Option f(final StringBuilder s) { + return fromString(s.toString()).toOption(); + } + }; + + /** + * A function that converts string builders to eithers. + * + * @return A function that converts string builders to eithers. + */ + public static F, F>> StringBuilder_Either() { + return new F, F>>() { + public F> f(final P1 a) { + return new F>() { + public Either f(final StringBuilder s) { + return fromString(s.toString()).toEither(a); + } + }; + } + }; + } + + /** + * A function that converts string builders to strings. + */ + public static final F StringBuilder_String = new F() { + public String f(final StringBuilder s) { + return s.toString(); + } + }; + + /** + * A function that converts string builders to string buffers. + */ + public static final F StringBuilder_StringBuffer = new F() { + public StringBuffer f(final StringBuilder s) { + return new StringBuffer(s); + } + }; + + // END StringBuilder -> + + + // BEGIN Try + + public static SafeIO> Try_SafeIO(Try0 t) { + return F_SafeIO(u -> Try.f(t)._1()); + } + + public static F, SafeIO>> Try_SafeIO() { + return t -> Try_SafeIO(t); + } + + public static IO Try_IO(Try0 t) { + return () -> t.f(); + } + + public static F, IO> Try_IO() { + return t -> Try_IO(t); + } + + public static F> Try_F(Try1 t) { + return Try.f(t); + } + + public static F, F>> Try_F() { + return t -> Try_F(t); + } + + // END Try + + // BEGIN TryEffect + + static public P1> TryEffect_P(final TryEffect0 t) { + return TryEffect.f(t); + } + + + // END TryEffect + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Either.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Either.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,804 @@ +package fj.data; + +import static fj.Bottom.error; +import fj.Effect; +import fj.F; +import static fj.Function.identity; +import static fj.P.p; + +import fj.Show; +import fj.Function; +import fj.P1; +import fj.Unit; +import fj.function.Effect1; + +import static fj.Unit.unit; +import static fj.data.Array.mkArray; +import static fj.data.List.single; +import static fj.data.List.cons_; +import static fj.data.Option.some; + +import java.util.Collection; +import java.util.Iterator; + +/** + * The Either type represents a value of one of two possible types (a disjoint union). + * The data constructors; Left and Right represent the two possible + * values. The Either type is often used as an alternative to + * scala.Option where Left represents failure (by convention) and + * Right is akin to Some. + * + * @version %build.number% + */ +public abstract class Either { + private Either() { + + } + + /** + * Projects this either as a left. + * + * @return A left projection of this either. + */ + public final LeftProjection left() { + return new LeftProjection(this); + } + + /** + * Projects this either as a right. + * + * @return A right projection of this either. + */ + public final RightProjection right() { + return new RightProjection(this); + } + + /** + * Returns true if this either is a left, false otherwise. + * + * @return true if this either is a left, false otherwise. + */ + public abstract boolean isLeft(); + + /** + * Returns true if this either is a right, false otherwise. + * + * @return true if this either is a right, false otherwise. + */ + public abstract boolean isRight(); + + /** + * The catamorphism for either. Folds over this either breaking into left or right. + * + * @param left The function to call if this is left. + * @param right The function to call if this is right. + * @return The reduced value. + */ + public final X either(final F left, final F right) { + return isLeft() ? + left.f(left().value()) : + right.f(right().value()); + } + + /** + * If this is a left, then return the left value in right, or vice versa. + * + * @return The value of this either swapped to the opposing side. + */ + public final Either swap() { + return isLeft() ? new Right(((Left) this).a) : new Left(((Right) this).b); + } + + private static final class Left extends Either { + private final A a; + + Left(final A a) { + this.a = a; + } + + public boolean isLeft() { + return true; + } + + public boolean isRight() { + return false; + } + } + + private static final class Right extends Either { + private final B b; + + Right(final B b) { + this.b = b; + } + + public boolean isLeft() { + return false; + } + + public boolean isRight() { + return true; + } + } + + /** + * A left projection of an either value. + */ + public final class LeftProjection implements Iterable { + private final Either e; + + private LeftProjection(final Either e) { + this.e = e; + } + + /** + * Returns an iterator for this projection. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this projection. + */ + public Iterator iterator() { + return toCollection().iterator(); + } + + /** + * The either value underlying this projection. + * + * @return The either value underlying this projection. + */ + public Either either() { + return e; + } + + /** + * Returns the value of this projection or fails with the given error message. + * + * @param err The error message to fail with. + * @return The value of this projection + */ + public A valueE(final P1 err) { + if (e.isLeft()) + //noinspection CastToConcreteClass + return ((Left) e).a; + else + throw error(err._1()); + } + + /** + * Returns the value of this projection or fails with the given error message. + * + * @param err The error message to fail with. + * @return The value of this projection + */ + public A valueE(final String err) { + return valueE(p(err)); + } + + /** + * The value of this projection or fails with a specialised error message. + * + * @return The value of this projection. + */ + public A value() { + return valueE(p("left.value on Right")); + } + + /** + * The value of this projection or the given argument. + * + * @param a The value to return if this projection has no value. + * @return The value of this projection or the given argument. + */ + public A orValue(final P1 a) { + return isLeft() ? value() : a._1(); + } + + /** + * The value of this projection or the given argument. + * + * @param a The value to return if this projection has no value. + * @return The value of this projection or the given argument. + */ + public A orValue(final A a) { + return isLeft() ? value() : a; + } + + /** + * The value of this projection or the result of the given function on the opposing projection's + * value. + * + * @param f The function to execute if this projection has no value. + * @return The value of this projection or the result of the given function on the opposing projection's + * value. + */ + public A on(final F f) { + return isLeft() ? value() : f.f(e.right().value()); + } + + /** + * Execute a side-effect on this projection's value if it has one. + * + * @param f The side-effect to execute. + * @return The unit value. + */ + public Unit foreach(final F f) { + if (isLeft()) + f.f(value()); + + return unit(); + } + + /** + * Execute a side-effect on this projection's value if it has one. + * + * @param f The side-effect to execute. + */ + public void foreachDoEffect(final Effect1 f) { + if (isLeft()) + f.f(value()); + } + + /** + * Map the given function across this projection's value if it has one. + * + * @param f The function to map across this projection. + * @return A new either value after mapping. + */ + public Either map(final F f) { + return isLeft() ? new Left(f.f(value())) : new Right(e.right().value()); + } + + /** + * Binds the given function across this projection's value if it has one. + * + * @param f The function to bind across this projection. + * @return A new either value after binding. + */ + public Either bind(final F> f) { + return isLeft() ? f.f(value()) : new Right(e.right().value()); + } + + /** + * Anonymous bind through this projection. + * + * @param e The value to bind with. + * @return An either after binding through this projection. + */ + public Either sequence(final Either e) { + return bind(Function.>constant(e)); + } + + /** + * Returns None if this projection has no value or if the given predicate + * p does not hold for the value, otherwise, returns a right in Some. + * + * @param f The predicate function to test on this projection's value. + * @return None if this projection has no value or if the given predicate + * p does not hold for the value, otherwise, returns a right in Some. + */ + public Option> filter(final F f) { + return isLeft() ? + f.f(value()) ? + Option.>some(new Left(value())) : + Option.>none() : + Option.>none(); + } + + /** + * Function application on this projection's value. + * + * @param e The either of the function to apply on this projection's value. + * @return The result of function application within either. + */ + public Either apply(final Either, B> e) { + return e.left().bind(new F, Either>() { + public Either f(final F f) { + return map(f); + } + }); + } + + /** + * Returns true if no value or returns the result of the application of the given + * function to the value. + * + * @param f The predicate function to test on this projection's value. + * @return true if no value or returns the result of the application of the given + * function to the value. + */ + public boolean forall(final F f) { + return isRight() || f.f(value()); + } + + /** + * Returns false if no value or returns the result of the application of the given + * function to the value. + * + * @param f The predicate function to test on this projection's value. + * @return false if no value or returns the result of the application of the given + * function to the value. + */ + public boolean exists(final F f) { + return isLeft() && f.f(value()); + } + + /** + * Returns a single element list if this projection has a value, otherwise an empty list. + * + * @return A single element list if this projection has a value, otherwise an empty list. + */ + public List toList() { + return isLeft() ? single(value()) : List.nil(); + } + + /** + * Returns this projection's value in Some if it exists, otherwise + * None. + * + * @return This projection's value in Some if it exists, otherwise + * None. + */ + public Option toOption() { + return isLeft() ? some(value()) : Option.none(); + } + + /** + * Returns a single element array if this projection has a value, otherwise an empty array. + * + * @return A single element array if this projection has a value, otherwise an empty array. + */ + public Array toArray() { + if (isLeft()) { + final Object[] a = new Object[1]; + a[0] = value(); + return mkArray(a); + } else + return mkArray(new Object[0]); + } + + /** + * Returns a single element stream if this projection has a value, otherwise an empty stream. + * + * @return A single element stream if this projection has a value, otherwise an empty stream. + */ + public Stream toStream() { + return isLeft() ? Stream.single(value()) : Stream.nil(); + } + + /** + * Projects an immutable collection of this projection. + * + * @return An immutable collection of this projection. + */ + public Collection toCollection() { + return toList().toCollection(); + } + } + + /** + * A right projection of an either value. + */ + public final class RightProjection implements Iterable { + private final Either e; + + private RightProjection(final Either e) { + this.e = e; + } + + /** + * Returns an iterator for this projection. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this projection. + */ + public Iterator iterator() { + return toCollection().iterator(); + } + + /** + * The either value underlying this projection. + * + * @return The either value underlying this projection. + */ + public Either either() { + return e; + } + + /** + * Returns the value of this projection or fails with the given error message. + * + * @param err The error message to fail with. + * @return The value of this projection + */ + public B valueE(final P1 err) { + if (e.isRight()) + //noinspection CastToConcreteClass + return ((Right) e).b; + else + throw error(err._1()); + } + + /** + * The value of this projection or fails with a specialised error message. + * + * @return The value of this projection. + */ + public B value() { + return valueE(p("right.value on Left")); + } + + /** + * The value of this projection or the given argument. + * + * @param b The value to return if this projection has no value. + * @return The value of this projection or the given argument. + */ + public B orValue(final P1 b) { + return isRight() ? value() : b._1(); + } + + /** + * The value of this projection or the result of the given function on the opposing projection's + * value. + * + * @param f The function to execute if this projection has no value. + * @return The value of this projection or the result of the given function on the opposing projection's + * value. + */ + public B on(final F f) { + return isRight() ? value() : f.f(e.left().value()); + } + + /** + * Execute a side-effect on this projection's value if it has one. + * + * @param f The side-effect to execute. + * @return The unit value. + */ + public Unit foreach(final F f) { + if (isRight()) + f.f(value()); + + return unit(); + } + + /** + * Execute a side-effect on this projection's value if it has one. + * + * @param f The side-effect to execute. + */ + public void foreachDoEffect(final Effect1 f) { + if (isRight()) + f.f(value()); + } + + /** + * Map the given function across this projection's value if it has one. + * + * @param f The function to map across this projection. + * @return A new either value after mapping. + */ + public Either map(final F f) { + return isRight() ? new Right(f.f(value())) : new Left(e.left().value()); + } + + /** + * Binds the given function across this projection's value if it has one. + * + * @param f The function to bind across this projection. + * @return A new either value after binding. + */ + public Either bind(final F> f) { + return isRight() ? f.f(value()) : new Left(e.left().value()); + } + + + /** + * Anonymous bind through this projection. + * + * @param e The value to bind with. + * @return An either after binding through this projection. + */ + public Either sequence(final Either e) { + return bind(Function.>constant(e)); + } + + /** + * Returns None if this projection has no value or if the given predicate + * p does not hold for the value, otherwise, returns a left in Some. + * + * @param f The predicate function to test on this projection's value. + * @return None if this projection has no value or if the given predicate + * p does not hold for the value, otherwise, returns a left in Some. + */ + public Option> filter(final F f) { + return isRight() ? + f.f(value()) ? + Option.>some(new Right(value())) : + Option.>none() : + Option.>none(); + } + + /** + * Function application on this projection's value. + * + * @param e The either of the function to apply on this projection's value. + * @return The result of function application within either. + */ + public Either apply(final Either> e) { + return e.right().bind(new F, Either>() { + public Either f(final F f) { + return map(f); + } + }); + } + + /** + * Returns true if no value or returns the result of the application of the given + * function to the value. + * + * @param f The predicate function to test on this projection's value. + * @return true if no value or returns the result of the application of the given + * function to the value. + */ + public boolean forall(final F f) { + return isLeft() || f.f(value()); + } + + /** + * Returns false if no value or returns the result of the application of the given + * function to the value. + * + * @param f The predicate function to test on this projection's value. + * @return false if no value or returns the result of the application of the given + * function to the value. + */ + public boolean exists(final F f) { + return isRight() && f.f(value()); + } + + /** + * Returns a single element list if this projection has a value, otherwise an empty list. + * + * @return A single element list if this projection has a value, otherwise an empty list. + */ + public List toList() { + return isRight() ? single(value()) : List.nil(); + } + + /** + * Returns this projection's value in Some if it exists, otherwise + * None. + * + * @return This projection's value in Some if it exists, otherwise + * None. + */ + public Option toOption() { + return isRight() ? some(value()) : Option.none(); + } + + /** + * Returns a single element array if this projection has a value, otherwise an empty array. + * + * @return A single element array if this projection has a value, otherwise an empty array. + */ + public Array toArray() { + if (isRight()) { + final Object[] a = new Object[1]; + a[0] = value(); + return mkArray(a); + } else + return Array.empty(); + } + + /** + * Returns a single element stream if this projection has a value, otherwise an empty stream. + * + * @return A single element stream if this projection has a value, otherwise an empty stream. + */ + public Stream toStream() { + return isRight() ? Stream.single(value()) : Stream.nil(); + } + + /** + * Projects an immutable collection of this projection. + * + * @return An immutable collection of this projection. + */ + public Collection toCollection() { + return toList().toCollection(); + } + } + + /** + * Construct a left value of either. + * + * @param a The value underlying the either. + * @return A left value of either. + */ + public static Either left(final A a) { + return new Left(a); + } + + /** + * A function that constructs a left value of either. + * + * @return A function that constructs a left value of either. + */ + public static F> left_() { + return new F>() { + public Either f(final A a) { + return left(a); + } + }; + } + + /** + * A function that constructs a right value of either. + * + * @return A function that constructs a right value of either. + */ + public static F> right_() { + return new F>() { + public Either f(final B b) { + return right(b); + } + }; + } + + /** + * Construct a right value of either. + * + * @param b The value underlying the either. + * @return A right value of either. + */ + public static Either right(final B b) { + return new Right(b); + } + + /** + * @return A function that maps another function across an either's left projection. + */ + public static F, F, Either>> leftMap_() { + return new F, F, Either>>() { + public F, Either> f(final F axf) { + return new F, Either>() { + public Either f(final Either e) { + return e.left().map(axf); + } + }; + } + }; + } + + /** + * @return A function that maps another function across an either's right projection. + */ + public static F, F, Either>> rightMap_() { + return new F, F, Either>>() { + public F, Either> f(final F axf) { + return new F, Either>() { + public Either f(final Either e) { + return e.right().map(axf); + } + }; + } + }; + } + + /** + * Joins an either through left. + * + * @param e The either of either to join. + * @return An either after joining. + */ + public static Either joinLeft(final Either, B> e) { + final F, Either> id = identity(); + return e.left().bind(id); + } + + /** + * Joins an either through right. + * + * @param e The either of either to join. + * @return An either after joining. + */ + public static Either joinRight(final Either> e) { + final F, Either> id = identity(); + return e.right().bind(id); + } + + /** + * Sequences through the left side of the either monad with a list of values. + * + * @param a The list of values to sequence with the either monad. + * @return A sequenced value. + */ + public static Either, X> sequenceLeft(final List> a) { + return a.isEmpty() ? + Either., X>left(List.nil()) : + a.head().left().bind(new F, X>>() { + public Either, X> f(final A aa) { + return sequenceLeft(a.tail()).left().map(cons_(aa)); + } + }); + } + + /** + * Sequences through the right side of the either monad with a list of values. + * + * @param a The list of values to sequence with the either monad. + * @return A sequenced value. + */ + public static Either> sequenceRight(final List> a) { + return a.isEmpty() ? + Either.>right(List.nil()) : + a.head().right().bind(new F>>() { + public Either> f(final B bb) { + return sequenceRight(a.tail()).right().map(cons_(bb)); + } + }); + } + + /** + * Takes an Either to its contained value within left or right. + * + * @param e The either to reduce. + * @return An Either to its contained value within left or right. + */ + public static A reduce(final Either e) { + return e.isLeft() ? e.left().value() : e.right().value(); + } + + /** + * If the condition satisfies, return the given A in left, otherwise, return the given B in right. + * + * @param c The condition to test. + * @param right The right value to use if the condition satisfies. + * @param left The left value to use if the condition does not satisfy. + * @return A constructed either based on the given condition. + */ + public static Either iif(final boolean c, final P1 right, final P1 left) { + return c ? new Right(right._1()) : new Left(left._1()); + } + + /** + * Returns all the left values in the given list. + * + * @param es The list of possible left values. + * @return All the left values in the given list. + */ + public static List lefts(final List> es) { + return es.foldRight(new F, F, List>>() { + public F, List> f(final Either e) { + return new F, List>() { + public List f(final List as) { + return e.isLeft() ? as.cons(e.left().value()) : as; + } + }; + } + }, List.nil()); + } + + /** + * Returns all the right values in the given list. + * + * @param es The list of possible right values. + * @return All the right values in the given list. + */ + public static List rights(final List> es) { + return es.foldRight(new F, F, List>>() { + public F, List> f(final Either e) { + return new F, List>() { + public List f(final List bs) { + return e.isRight() ? bs.cons(e.right().value()) : bs; + } + }; + } + }, List.nil()); + } + + public String toString() { + return Show.eitherShow(Show.anyShow(), Show.anyShow()).showS(this); + } + +} + diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Enumerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Enumerator.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,446 @@ +package fj.data; + +import fj.F; +import fj.F2; +import static fj.Function.*; +import static fj.data.Option.none; +import static fj.data.Option.some; + +import fj.Function; +import fj.Ord; + +import static fj.Ord.*; +import fj.Ordering; +import static fj.Ordering.*; + +import java.math.BigDecimal; +import java.math.BigInteger; + +/** + * Abstracts over a type that may have a successor and/or predecessor value. This implies ordering for that type. A user + * may construct an enumerator with an optimised version for plus, otherwise a default is implemented using + * the given successor/predecessor implementations. + *

+ * For any enumerator e, the following laws must satisfy: + *

+ * + * @version %build.number% + */ +public final class Enumerator { + private final F> successor; + private final F> predecessor; + private final Option max; + private final Option min; + private final Ord order; + private final F>> plus; + + private Enumerator(final F> successor, final F> predecessor, final Option max, + final Option min, final Ord order, final F>> plus) { + this.successor = successor; + this.predecessor = predecessor; + this.max = max; + this.min = min; + this.order = order; + this.plus = plus; + } + + /** + * Returns the potential successor of a value for this enumerator in curried form. + * + * @return The potential successor of a value for this enumerator in curried form. + */ + public F> successor() { + return successor; + } + + /** + * Returns the potential successor of a value for this enumerator. + * + * @param a The value to return the successor of. + * @return The potential successor of a value for this enumerator. + */ + public Option successor(final A a) { + return successor.f(a); + } + + /** + * Returns the potential predecessor of a value for this enumerator in curried form. + * + * @return The potential predecessor of a value for this enumerator in curried form. + */ + public F> predecessor() { + return predecessor; + } + + /** + * Returns the potential predecessor of a value for this enumerator. + * + * @param a The value to return the predecessor of. + * @return The potential predecessor of a value for this enumerator. + */ + public Option predecessor(final A a) { + return predecessor.f(a); + } + + /** + * Returns the maximum value for this enumerator if there is one. + * + * @return The maximum value for this enumerator if there is one. + */ + public Option max() { + return max; + } + + /** + * Returns the minimum value for this enumerator if there is one. + * + * @return The minimum value for this enumerator if there is one. + */ + public Option min() { + return min; + } + + /** + * Returns a function that moves a value along the enumerator a given number of times. + * + * @return A function that moves a value along the enumerator a given number of times. + */ + public F>> plus() { + return plus; + } + + /** + * Returns a function that moves a value along the enumerator a given number of times. + * + * @param a The value to begin moving along from. + * @return A function that moves a value along the enumerator a given number of times. + */ + public F> plus(final A a) { + return plus.f(a); + } + + /** + * Returns a function that moves a value along the enumerator a given number of times. + * + * @param l The number of times to move along the enumerator. + * @return A function that moves a value along the enumerator a given number of times. + */ + public F> plus(final long l) { + return flip(plus).f(l); + } + + /** + * Moves a value along the enumerator a given number of times. + * + * @param a The value to begin moving along from. + * @param l The number of times to move along the enumerator. + * @return A potential value after having moved the given number of times. + */ + public Option plus(final A a, final long l) { + return plus.f(a).f(l); + } + + /** + * Returns the ordering for the enumerator. + * + * @return The ordering for the enumerator. + */ + public Ord order() { + return order; + } + + /** + * Invariant functor map over this enumerator. + * + * @param f The covariant map. + * @param g The contra-variant map. + * @return An enumerator after the given functions are applied. + */ + public Enumerator xmap(final F f, final F g) { + final F, Option> of = new F, Option>() { + public Option f(final Option o) { + return o.map(f); + } + }; + return enumerator(compose(compose(of, successor), g), + compose(compose(of, predecessor), g), + max.map(f), + min.map(f), + order.comap(g), + compose(compose(Function., Option>compose().f(of), plus), g)); + } + + /** + * Returns a stream of the values from this enumerator, starting at the given value, counting up. + * + * @param a A value at which to begin the stream. + * @return a stream of the values from this enumerator, starting at the given value, counting up. + */ + public Stream toStream(final A a) { + final F id = identity(); + return Stream.fromFunction(this, id, a); + } + + /** + * Create a new enumerator with the given minimum value. + * + * @param min A minimum value. + * @return A new enumerator identical to this one, but with the given minimum value. + */ + public Enumerator setMin(final Option min) { + return enumerator(successor, predecessor, max, min, order, plus); + } + + /** + * Create a new enumerator with the given maximum value. + * + * @param max A maximum value. + * @return A new enumerator identical to this one, but with the given maximum value. + */ + public Enumerator setMax(final Option max) { + return enumerator(successor, predecessor, max, min, order, plus); + } + + /** + * Construct an enumerator. ` + * + * @param successor The successor function. + * @param predecessor The predecessor function. + * @param max The potential maximum value. + * @param min The potential minimum value. + * @param order The ordering for the type. + * @param plus The function to move the enumeration a given number of times. This may be supplied for a performance + * enhancement for certain types. + * @return An enumerator with the given values. + */ + public static Enumerator enumerator(final F> successor, final F> predecessor, + final Option max, final Option min, final Ord order, + final F>> plus) { + return new Enumerator(successor, predecessor, max, min, order, plus); + } + + /** + * Construct an enumerator. The plus function is derived from the successor and + * predecessor. + * + * @param successor The successor function. + * @param predecessor The predecessor function. + * @param max The potential maximum value. + * @param min The potential minimum value. + * @param order The ordering for the type. + * @return An enumerator with the given values. + */ + public static Enumerator enumerator(final F> successor, final F> predecessor, + final Option max, final Option min, final Ord order) { + return new Enumerator(successor, predecessor, max, min, order, curry(new F2>() { + public Option f(final A a, final Long l) { + if (l == 0L) + return some(a); + else if (l < 0L) { + A aa = a; + for (long x = l; x < 0; x++) { + final Option s = predecessor.f(aa); + if (s.isNone()) + return none(); + else + aa = s.some(); + } + return some(aa); + } else { + A aa = a; + for (long x = l; x > 0; x--) { + final Option s = successor.f(aa); + if (s.isNone()) + return none(); + else + aa = s.some(); + } + return some(aa); + } + } + })); + } + + /** + * An enumerator for boolean. + */ + public static final Enumerator booleanEnumerator = enumerator(new F>() { + public Option f(final Boolean b) { + return b ? Option.none() : some(true); + } + }, new F>() { + public Option f(final Boolean b) { + return b ? some(false) : Option.none(); + } + }, some(true), some(false), booleanOrd); + + /** + * An enumerator for byte. + */ + public static final Enumerator byteEnumerator = enumerator(new F>() { + public Option f(final Byte b) { + return b == Byte.MAX_VALUE ? Option.none() : some((byte) (b + 1)); + } + }, new F>() { + public Option f(final Byte b) { + return b == Byte.MIN_VALUE ? Option.none() : some((byte) (b - 1)); + } + }, some(Byte.MAX_VALUE), some(Byte.MIN_VALUE), byteOrd); + + /** + * An enumerator for char. + */ + public static final Enumerator charEnumerator = enumerator(new F>() { + public Option f(final Character c) { + return c == Character.MAX_VALUE ? Option.none() : some((char) (c + 1)); + } + }, new F>() { + public Option f(final Character c) { + return c == Character.MIN_VALUE ? Option.none() : some((char) (c - 1)); + } + }, some(Character.MAX_VALUE), some(Character.MIN_VALUE), charOrd); + + /** + * An enumerator for double. + */ + public static final Enumerator doubleEnumerator = enumerator(new F>() { + public Option f(final Double d) { + return d == Double.MAX_VALUE ? Option.none() : some(d + 1D); + } + }, new F>() { + public Option f(final Double d) { + return d == Double.MIN_VALUE ? Option.none() : some(d - 1D); + } + }, some(Double.MAX_VALUE), some(Double.MIN_VALUE), doubleOrd); + + /** + * An enumerator for float. + */ + public static final Enumerator floatEnumerator = enumerator(new F>() { + public Option f(final Float f) { + return f == Float.MAX_VALUE ? Option.none() : some(f + 1F); + } + }, new F>() { + public Option f(final Float f) { + return f == Float.MIN_VALUE ? Option.none() : some(f - 1F); + } + }, some(Float.MAX_VALUE), some(Float.MIN_VALUE), floatOrd); + + /** + * An enumerator for int. + */ + public static final Enumerator intEnumerator = enumerator(new F>() { + public Option f(final Integer i) { + return i == Integer.MAX_VALUE ? Option.none() : some(i + 1); + } + }, new F>() { + public Option f(final Integer i) { + return i == Integer.MIN_VALUE ? Option.none() : some(i - 1); + } + }, some(Integer.MAX_VALUE), some(Integer.MIN_VALUE), intOrd); + + /** + * An enumerator for BigInteger. + */ + public static final Enumerator bigintEnumerator = enumerator(new F>() { + public Option f(final BigInteger i) { + return some(i.add(BigInteger.ONE)); + } + }, new F>() { + public Option f(final BigInteger i) { + return some(i.subtract(BigInteger.ONE)); + } + }, Option.none(), Option.none(), bigintOrd, curry( + new F2>() { + public Option f(final BigInteger i, final Long l) { + return some(i.add(BigInteger.valueOf(l))); + } + })); + + /** + * An enumerator for BigDecimal. + */ + public static final Enumerator bigdecimalEnumerator = enumerator(new F>() { + public Option f(final BigDecimal i) { + return some(i.add(BigDecimal.ONE)); + } + }, new F>() { + public Option f(final BigDecimal i) { + return some(i.subtract(BigDecimal.ONE)); + } + }, Option.none(), Option.none(), bigdecimalOrd, curry( + new F2>() { + public Option f(final BigDecimal d, final Long l) { + return some(d.add(BigDecimal.valueOf(l))); + } + })); + + /** + * An enumerator for long. + */ + public static final Enumerator longEnumerator = enumerator(new F>() { + public Option f(final Long i) { + return i == Long.MAX_VALUE ? Option.none() : some(i + 1L); + } + }, new F>() { + public Option f(final Long i) { + return i == Long.MIN_VALUE ? Option.none() : some(i - 1L); + } + }, some(Long.MAX_VALUE), some(Long.MIN_VALUE), longOrd); + + /** + * An enumerator for short. + */ + public static final Enumerator shortEnumerator = enumerator(new F>() { + public Option f(final Short i) { + return i == Short.MAX_VALUE ? Option.none() : some((short) (i + 1)); + } + }, new F>() { + public Option f(final Short i) { + return i == Short.MIN_VALUE ? Option.none() : some((short) (i - 1)); + } + }, some(Short.MAX_VALUE), some(Short.MIN_VALUE), shortOrd); + + /** + * An enumerator for Ordering. + */ + public static final Enumerator orderingEnumerator = enumerator(new F>() { + public Option f(final Ordering o) { + return o == LT ? some(EQ) : o == EQ ? some(GT) : Option.none(); + } + }, new F>() { + public Option f(final Ordering o) { + return o == GT ? some(EQ) : o == EQ ? some(LT) : Option.none(); + } + }, some(GT), some(LT), orderingOrd); + + /** + * An enumerator for Natural + */ + public static final Enumerator naturalEnumerator = enumerator(new F>() { + public Option f(final Natural n) { + return Option.some(n.succ()); + } + }, new F>() { + public Option f(final Natural n) { + return n.pred(); + } + }, Option.none(), some(Natural.ZERO), naturalOrd, curry(new F2>() { + public Option f(final Natural n, final Long l) { + return some(n).apply(Natural.natural(l).map(Function.curry(new F2() { + public Natural f(final Natural n1, final Natural n2) { + return n1.add(n2); + } + }))); + } + })); + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/HashMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/HashMap.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,350 @@ +package fj.data; + +import fj.*; +import fj.function.Effect1; + +import java.util.Collection; +import java.util.Iterator; + +import static fj.P.p; +import static fj.data.Option.fromNull; + +/** + * A mutable hash map providing O(1) lookup. + * + * @version %build.number% + * @see java.util.HashMap + */ +public final class HashMap implements Iterable { + private final class Key { + private final K k; + private final Equal e; + private final Hash h; + + Key(final K k, final Equal e, final Hash h) { + this.k = k; + this.e = e; + this.h = h; + } + + K k() { + return k; + } + + @SuppressWarnings({"unchecked"}) + public boolean equals(final Object o) { + return o instanceof Key && e.eq(k, (K) ((Key) o).k()); + } + + public int hashCode() { + return h.hash(k); + } + } + + /** + * Returns an iterator for this map's keys. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this map's keys. + */ + public Iterator iterator() { + return keys().iterator(); + } + + private final java.util.HashMap, V> m; + + private final Equal e; + private final Hash h; + + /** + * Construct a hash map with the given equality and hashing strategy. + * + * @param e The equality strategy. + * @param h The hashing strategy. + */ + public HashMap(final Equal e, final Hash h) { + m = new java.util.HashMap, V>(); + this.e = e; + this.h = h; + } + + public HashMap(java.util.Map map, final Equal e, final Hash h) { + this(e, h); + for (K key : map.keySet()) { + set(key, map.get(key)); + } + } + + /** + * Construct a hash map with the given equality and hashing strategy. + * + * @param e The equality strategy. + * @param h The hashing strategy. + * @param initialCapacity The initial capacity. + */ + public HashMap(final Equal e, final Hash h, final int initialCapacity) { + m = new java.util.HashMap, V>(initialCapacity); + this.e = e; + this.h = h; + } + + public HashMap(java.util.Map map) { + this(map, Equal.anyEqual(), Hash.anyHash()); + } + + /** + * Construct a hash map with the given equality and hashing strategy. + * + * @param e The equality strategy. + * @param h The hashing strategy. + * @param initialCapacity The initial capacity. + * @param loadFactor The load factor. + */ + public HashMap(final Equal e, final Hash h, final int initialCapacity, final float loadFactor) { + m = new java.util.HashMap, V>(initialCapacity, loadFactor); + this.e = e; + this.h = h; + } + + /** + * Construct a hash map that uses {@link Object#equals} and {@link Object#hashCode}. + * + * @return A new hash map that uses {@link Object#equals} and {@link Object#hashCode}. + */ + public static HashMap hashMap() { + final Equal e = Equal.anyEqual(); + final Hash h = Hash.anyHash(); + return new HashMap(e, h); + } + + /** + * Compare two key values for equality using the underlying equality strategy. + * + * @param k1 One key value to compare. + * @param k2 The other key value to compare. + * @return true if the two key values are equal, false otherwise. + */ + public boolean eq(final K k1, final K k2) { + return e.eq(k1, k2); + } + + /** + * Compute the hash of the given key value using the underlying hashing strategy. + * + * @param k The key value to computer the hash of. + * @return The hash of the given key value. + */ + public int hash(final K k) { + return h.hash(k); + } + + /** + * Returns a potential value that the given key maps to. + * + * @param k The key to look up in the hash map. + * @return A potential value for the given key. + */ + public Option get(final K k) { + return fromNull(m.get(new Key(k, e, h))); + } + + /** + * A curried version of {@link #get(Object)}. + * + * @return A curried version of {@link #get(Object)}. + */ + public F> get() { + return new F>() { + public Option f(final K k) { + return get(k); + } + }; + } + + /** + * Clear all entries from this hash map. + */ + public void clear() { + m.clear(); + } + + /** + * Determines if the given key value exists in this hash map. + * + * @param k The key value to look for in this hash map. + * @return true if this hash map contains the given key, false otherwise. + */ + public boolean contains(final K k) { + return m.containsKey(new Key(k, e, h)); + } + + /** + * Returns all key entries in this hash map. + * + * @return All key entries in this hash map. + */ + public List keys() { + final List.Buffer b = new List.Buffer(); + + for (final Key k : m.keySet()) { + b.snoc(k.k()); + } + + return b.toList(); + } + + /** + * Returns all values in this hash map. + * + * @return All values in this hash map. + */ + public List values() { + return keys().map(new F() { + public V f(final K k) { + return m.get(new Key(k, e, h)); + } + }); + } + + /** + * Determines if this hash map has any entries. + * + * @return true if this hash map has no entries, false otherwise. + */ + public boolean isEmpty() { + return m.isEmpty(); + } + + /** + * Returns the number of entries in this hash map. + * + * @return The number of entries in this hash map. + */ + public int size() { + return m.size(); + } + + /** + * Inserts the given key and value association into the hash map. + * + * @param k The key to insert. + * @param v The value to insert. + */ + public void set(final K k, final V v) { + if (v != null) { + m.put(new Key(k, e, h), v); + } + } + + /** + * Deletes the entry in the hash map that corresponds to the given key. + * + * @param k The key to delete from this hash map. + */ + public void delete(final K k) { + m.remove(new Key(k, e, h)); + } + + /** + * Deletes the entry in the hash map that corresponds to the given key and returns any associated value. + * + * @param k The key to delete from this hash map. + * @return The value that was associated with the given key, if there was one. + */ + public Option getDelete(final K k) { + return fromNull(m.remove(new Key(k, e, h))); + } + + public HashMap map(F keyFunction, + F valueFunction, + Equal equal, Hash hash) { + final HashMap hashMap = new HashMap(equal, hash); + for (K key : keys()) { + final A newKey = keyFunction.f(key); + final B newValue = valueFunction.f(get(key).some()); + hashMap.set(newKey, newValue); + } + return hashMap; + } + + public HashMap map(F keyFunction, + F valueFunction) { + return map(keyFunction, valueFunction, Equal.anyEqual(), Hash.anyHash()); + } + + public HashMap map(F, P2> function, Equal equal, Hash hash) { + return from(toStream().map(function), equal, hash); + } + + public HashMap map(F, P2> function) { + return from(toStream().map(function)); + } + + public HashMap mapKeys(F keyFunction, Equal equal, Hash hash) { + return map(keyFunction, Function.identity(), equal, hash); + } + + public HashMap mapKeys(F function) { + return mapKeys(function, Equal.anyEqual(), Hash.anyHash()); + } + + public HashMap mapValues(F function) { + return map(Function.identity(), function, e, h); + } + + public void foreachDoEffect(Effect1> effect) { + toStream().foreachDoEffect(effect); + } + + public void foreach(F, Unit> function) { + toStream().foreach(function); + } + + public List> toList() { + return keys().map(new F>() { + public P2 f(final K k) { + return p(k, get(k).some()); + } + }); + } + + /** + * Projects an immutable collection of this hash map. + * + * @return An immutable collection of this hash map. + */ + public Collection> toCollection() { + return toList().toCollection(); + } + + public Stream> toStream() { + return toList().toStream(); + } + + public Option> toOption() { + return toList().toOption(); + } + + public Array> toArray() { + return toList().toArray(); + } + + public java.util.Map toMap() { + final java.util.HashMap result = new java.util.HashMap(); + for (K key : keys()) { + result.put(key, get(key).some()); + } + return result; + } + + public static HashMap from(Iterable> entries) { + return from(entries, Equal.anyEqual(), Hash.anyHash()); + } + + public static HashMap from(Iterable> entries, Equal equal, Hash hash) { + final HashMap map = new HashMap(equal, hash); + for (P2 entry : entries) { + map.set(entry._1(), entry._2()); + } + return map; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/HashSet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/HashSet.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,155 @@ +package fj.data; + +import fj.Equal; +import fj.Hash; +import fj.Unit; +import static fj.Unit.unit; + +import java.util.Collection; +import java.util.Iterator; + +/** + * A mutable hash set that guarantees uniqueness of its elements providing O(1) lookup. + * + * @version %build.number% + * @see HashMap + */ +public final class HashSet implements Iterable { + /** + * Returns an iterator for this hash set. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this hash set. + */ + public Iterator iterator() { + return toCollection().iterator(); + } + + private final HashMap m; + + /** + * Construct a hash set with the given equality and hashing strategy. + * + * @param e The equality strategy. + * @param h The hashing strategy. + */ + public HashSet(final Equal e, final Hash h) { + m = new HashMap(e, h); + } + + /** + * Construct a hash set with the given equality and hashing strategy. + * + * @param e The equality strategy. + * @param h The hashing strategy. + * @param initialCapacity The initial capacity. + */ + public HashSet(final Equal e, final Hash h, final int initialCapacity) { + m = new HashMap(e, h, initialCapacity); + } + + /** + * Construct a hash set with the given equality and hashing strategy. + * + * @param e The equality strategy. + * @param h The hashing strategy. + * @param initialCapacity The initial capacity. + * @param loadFactor The load factor. + */ + public HashSet(final Equal e, final Hash h, final int initialCapacity, final float loadFactor) { + m = new HashMap(e, h, initialCapacity, loadFactor); + } + + /** + * Compare two values for equality using the underlying equality strategy. + * + * @param a1 One value to compare. + * @param a2 The other value to compare. + * @return true if the two values are equal, false otherwise. + */ + public boolean eq(final A a1, final A a2) { + return m.eq(a1, a2); + } + + /** + * Compute the hash of the given value using the underlying hashing strategy. + * + * @param a The value to computer the hash of. + * @return The hash of the given value. + */ + public int hash(final A a) { + return m.hash(a); + } + + /** + * Determines if this hash set contains the given element. + * + * @param a The element to look for in this hash set. + * @return true if this hash set contains the given element, false otherwise. + */ + public boolean contains(final A a) { + return m.contains(a); + } + + /** + * Insert the given element into this hash set. + * + * @param a The element to insert. + */ + public void set(final A a) { + m.set(a, unit()); + } + + /** + * Clear all elements from this hash set. + */ + public void clear() { + m.clear(); + } + + /** + * Determines if this hash set contains any elements. + * + * @return true if this hash set contains no elements, false otherwise. + */ + public boolean isEmpty() { + return m.isEmpty(); + } + + /** + * Returns the number of entries in this hash set. + * + * @return The number of entries in this hash set. + */ + public int size() { + return m.size(); + } + + /** + * Deletes the given element from this hash set. + * + * @param a The element to delete from this hash set. + * @return true if this hash set contained the given element prior to deletion, false + * otherwise. + */ + public boolean delete(final A a) { + return m.getDelete(a).isSome(); + } + + /** + * Returns a list projection of this hash set. + * + * @return A list projection of this hash set. + */ + public List toList() { + return m.keys(); + } + + /** + * Projects an immutable collection of this hash set. + * + * @return An immutable collection of this hash set. + */ + public Collection toCollection() { + return toList().toCollection(); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/IO.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/IO.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,20 @@ +package fj.data; + +/** + * Created by MarkPerry on 19/06/2014. + */ + +import java.io.IOException; + +/** + * IO monad for processing files + * + * @author Martin Grotzke + * + * @param the type of the result produced by the IO + */ +public interface IO { + + public A run() throws IOException; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/IOFunctions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/IOFunctions.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,443 @@ +package fj.data; + +import static fj.Bottom.errorF; +import static fj.Function.constant; +import static fj.Function.partialApply2; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; +import java.util.Arrays; + +import fj.*; +import fj.data.Iteratee.Input; +import fj.data.Iteratee.IterV; +import fj.function.Try0; + +/** + * IO monad for processing files, with main methods {@link #enumFileLines }, + * {@link #enumFileChars} and {@link #enumFileCharChunks} + * (the latter one is the fastest as char chunks read from the file are directly passed to the iteratee + * without indirection in between). + * + * @author Martin Grotzke + * + */ +public class IOFunctions { + + private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; + + public static Try0 toTry(IO io) { + return () -> io.run(); + } + + public static P1> p(IO io) { + return Try.f(toTry(io)); + } + + public static IO io(P1 p) { + return () -> p._1(); + } + + public static IO io(Try0 t) { + return () -> t.f(); + } + + public static final F> closeReader = + new F>() { + @Override + public IO f(final Reader r) { + return closeReader(r); + } + }; + + public static IO closeReader(final Reader r) { + return new IO() { + @Override + public Unit run() throws IOException { + r.close(); + return Unit.unit(); + } + }; + } + + /** + * An IO monad that reads lines from the given file (using a {@link BufferedReader}) and passes + * lines to the provided iteratee. May not be suitable for files with very long + * lines, consider to use {@link #enumFileCharChunks} or {@link #enumFileChars} + * as an alternative. + * + * @param f the file to read, must not be null + * @param encoding the encoding to use, {@link Option#none()} means platform default + * @param i the iteratee that is fed with lines read from the file + */ + public static IO> enumFileLines(final File f, final Option encoding, final IterV i) { + return bracket(bufferedReader(f, encoding) + , Function.>vary(closeReader) + , partialApply2(IOFunctions.lineReader(), i)); + } + + /** + * An IO monad that reads char chunks from the given file and passes them to the given iteratee. + * + * @param f the file to read, must not be null + * @param encoding the encoding to use, {@link Option#none()} means platform default + * @param i the iteratee that is fed with char chunks read from the file + */ + public static IO> enumFileCharChunks(final File f, final Option encoding, final IterV i) { + return bracket(fileReader(f, encoding) + , Function.>vary(closeReader) + , partialApply2(IOFunctions.charChunkReader(), i)); + } + + /** + * An IO monad that reads char chunks from the given file and passes single chars to the given iteratee. + * + * @param f the file to read, must not be null + * @param encoding the encoding to use, {@link Option#none()} means platform default + * @param i the iteratee that is fed with chars read from the file + */ + public static IO> enumFileChars(final File f, final Option encoding, final IterV i) { + return bracket(fileReader(f, encoding) + , Function.>vary(closeReader) + , partialApply2(IOFunctions.charChunkReader2(), i)); + } + + public static IO bufferedReader(final File f, final Option encoding) { + return IOFunctions.map(fileReader(f, encoding), new F() { + @Override + public BufferedReader f(final Reader a) { + return new BufferedReader(a); + }}); + } + + public static IO fileReader(final File f, final Option encoding) { + return new IO() { + @Override + public Reader run() throws IOException { + final FileInputStream fis = new FileInputStream(f); + return encoding.isNone() ? new InputStreamReader(fis) : new InputStreamReader(fis, encoding.some()); + } + }; + } + + public static final IO bracket(final IO init, final F> fin, final F> body) { + return new IO() { + @Override + public C run() throws IOException { + final A a = init.run(); + try { + return body.f(a).run(); + } catch (final IOException e) { + throw e; + } finally { + fin.f(a); + } + } + }; + } + + public static final IO unit(final A a) { + return new IO() { + @Override + public A run() throws IOException { + return a; + } + }; + } + + public static final IO lazy(final P1 p) { + return () -> p._1(); + } + + public static final IO lazy(final F f) { + return () -> f.f(Unit.unit()); + } + + public static final SafeIO lazySafe(final F f) { + return () -> f.f(Unit.unit()); + } + + public static final SafeIO lazySafe(final P1 f) { + return () -> f._1(); + } + + /** + * A function that feeds an iteratee with lines read from a {@link BufferedReader}. + */ + public static F, IO>>> lineReader() { + final F, Boolean> isDone = + new F, Boolean>() { + final F>, P1> done = constant(P.p(true)); + final F, IterV>, P1> cont = constant(P.p(false)); + + @Override + public Boolean f(final IterV i) { + return i.fold(done, cont)._1(); + } + }; + + return new F, IO>>>() { + @Override + public F, IO>> f(final BufferedReader r) { + return new F, IO>>() { + final F>, P1>> done = errorF("iteratee is done"); //$NON-NLS-1$ + + @Override + public IO> f(final IterV it) { + // use loop instead of recursion because of missing TCO + return new IO>() { + @Override + public IterV run() throws IOException { + IterV i = it; + while (!isDone.f(i)) { + final String s = r.readLine(); + if (s == null) { return i; } + final Input input = Input.el(s); + final F, IterV>, P1>> cont = F1Functions.lazy(Function., IterV>apply(input)); + i = i.fold(done, cont)._1(); + } + return i; + } + }; + } + }; + } + }; + } + + /** + * A function that feeds an iteratee with character chunks read from a {@link Reader} + * (char[] of size {@link #DEFAULT_BUFFER_SIZE}). + */ + public static F, IO>>> charChunkReader() { + final F, Boolean> isDone = + new F, Boolean>() { + final F>, P1> done = constant(P.p(true)); + final F, IterV>, P1> cont = constant(P.p(false)); + + @Override + public Boolean f(final IterV i) { + return i.fold(done, cont)._1(); + } + }; + + return new F, IO>>>() { + @Override + public F, IO>> f(final Reader r) { + return new F, IO>>() { + final F>, P1>> done = errorF("iteratee is done"); //$NON-NLS-1$ + + @Override + public IO> f(final IterV it) { + // use loop instead of recursion because of missing TCO + return new IO>() { + @Override + public IterV run() throws IOException { + + IterV i = it; + while (!isDone.f(i)) { + char[] buffer = new char[DEFAULT_BUFFER_SIZE]; + final int numRead = r.read(buffer); + if (numRead == -1) { return i; } + if(numRead < buffer.length) { + buffer = Arrays.copyOfRange(buffer, 0, numRead); + } + final Input input = Input.el(buffer); + final F, IterV>, P1>> cont = + F1Functions.lazy(Function., IterV>apply(input)); + i = i.fold(done, cont)._1(); + } + return i; + } + }; + } + }; + } + }; + } + + /** + * A function that feeds an iteratee with characters read from a {@link Reader} + * (chars are read in chunks of size {@link #DEFAULT_BUFFER_SIZE}). + */ + public static F, IO>>> charChunkReader2() { + final F, Boolean> isDone = + new F, Boolean>() { + final F>, P1> done = constant(P.p(true)); + final F, IterV>, P1> cont = constant(P.p(false)); + + @Override + public Boolean f(final IterV i) { + return i.fold(done, cont)._1(); + } + }; + + return new F, IO>>>() { + @Override + public F, IO>> f(final Reader r) { + return new F, IO>>() { + final F>, IterV> done = errorF("iteratee is done"); //$NON-NLS-1$ + + @Override + public IO> f(final IterV it) { + // use loop instead of recursion because of missing TCO + return new IO>() { + @Override + public IterV run() throws IOException { + + IterV i = it; + while (!isDone.f(i)) { + char[] buffer = new char[DEFAULT_BUFFER_SIZE]; + final int numRead = r.read(buffer); + if (numRead == -1) { return i; } + if(numRead < buffer.length) { + buffer = Arrays.copyOfRange(buffer, 0, numRead); + } + for(int c = 0; c < buffer.length; c++) { + final Input input = Input.el(buffer[c]); + final F, IterV>, IterV> cont = + Function., IterV>apply(input); + i = i.fold(done, cont); + } + } + return i; + } + }; + } + }; + } + }; + } + + public static final IO map(final IO io, final F f) { + return new IO() { + @Override + public B run() throws IOException { + return f.f(io.run()); + } + }; + } + + public static final IO bind(final IO io, final F> f) { + return new IO() { + @Override + public B run() throws IOException { + return f.f(io.run()).run(); + } + }; + } + + /** + * Evaluate each action in the sequence from left to right, and collect the results. + */ + public static IO> sequence(List> list) { + F2, IO>, IO>> f2 = (io, ioList) -> + IOFunctions.bind(ioList, (xs) -> map(io, x -> List.cons(x, xs))); + return list.foldRight(f2, IOFunctions.unit(List.nil())); + } + + + public static IO> sequence(Stream> stream) { + F2>, IO, IO>> f2 = (ioList, io) -> + IOFunctions.bind(ioList, (xs) -> map(io, x -> Stream.cons(x, P.lazy(u -> xs)))); + return stream.foldLeft(f2, IOFunctions.unit(Stream.nil())); + } + + + /** + * Map each element of a structure to an action, evaluate these actions from left to right + * and collect the results. + */ + public static IO> traverse(List list, F> f) { + F2>, IO>> f2 = (a, acc) -> + bind(acc, (bs) -> map(f.f(a), b -> bs.append(List.list(b)))); + return list.foldRight(f2, IOFunctions.unit(List.nil())); + } + + public static IO join(IO> io1) { + return bind(io1, io2 -> io2); + } + + public static SafeIO> toSafeIO(IO io) { + return () -> Try.f(() -> io.run())._1(); + } + + public static IO append(final IO io1, final IO io2) { + return () -> { + io1.run(); + return io2.run(); + }; + } + + public static IO left(final IO io1, final IO io2) { + return () -> { + A a = io1.run(); + io2.run(); + return a; + }; + } + + public static IO flatMap(final IO io, final F> f) { + return bind(io, f); + } + + static IO> sequenceWhile(final Stream> stream, final F f) { + return new IO>() { + @Override + public Stream run() throws IOException { + boolean loop = true; + Stream> input = stream; + Stream result = Stream.nil(); + while (loop) { + if (input.isEmpty()) { + loop = false; + } else { + A a = input.head().run(); + if (!f.f(a)) { + loop = false; + } else { + input = input.tail()._1(); + result = result.cons(a); + } + } + } + return result.reverse(); + } + }; + } + + public static IO apply(IO io, IO> iof) { + return bind(iof, f -> map(io, a -> f.f(a))); + } + + public static IO liftM2(IO ioa, IO iob, F2 f) { + return bind(ioa, a -> map(iob, b -> f.f(a, b))); + } + + public static IO> replicateM(IO ioa, int n) { + return sequence(List.replicate(n, ioa)); + } + + public static IO>> readerState() { + return () -> State.unit((BufferedReader r) -> P.p(r, Try.f((BufferedReader r2) -> r2.readLine()).f(r))); + } + + public static final BufferedReader stdinBufferedReader = new BufferedReader(new InputStreamReader(System.in)); + + public static IO stdinReadLine() { + return () -> stdinBufferedReader.readLine(); + } + + public static IO stdoutPrintln(final String s) { + return () -> { + System.out.println(s); + return Unit.unit(); + }; + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/IterableW.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/IterableW.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,536 @@ +package fj.data; + +import static fj.data.Option.some; +import static fj.data.Stream.iterableStream; +import fj.Equal; +import fj.F; +import fj.F2; +import fj.F3; +import fj.P1; +import fj.P2; +import static fj.Function.curry; +import static fj.Function.identity; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +/** + * A wrapper for Iterable that equips it with some useful functions. + */ +public final class IterableW implements Iterable { + + private final Iterable i; + + private IterableW(final Iterable i) { + this.i = i; + } + + /** + * Wraps the given iterable. + * + * @param a The iterable to wrap. + * @return An iterable equipped with some useful functions. + */ + public static IterableW wrap(final Iterable a) { + return new IterableW(a); + } + + /** + * Provides a function that wraps the given iterable. + * + * @return A function that returns the given iterable, wrapped. + */ + public static > F> wrap() { + return new F>() { + public IterableW f(final T a) { + return wrap(a); + } + }; + } + + /** + * Returns an Iterable that completely preserves the argument. The unit function for Iterables. + * + * @param a A value to preserve in an Iterable. + * @return An Iterable that yields the argument when iterated over. + */ + public static IterableW iterable(final A a) { + return wrap(some(a)); + } + + /** + * Wraps a given function's return value in a Iterable. + * The Kleisli arrow for Iterables. + * + * @param f The function whose return value to wrap in a Iterable. + * @return The equivalent function whose return value is iterable. + */ + public static F> iterable(final F f) { + return new F>() { + public IterableW f(final A a) { + return iterable(f.f(a)); + } + }; + } + + /** + * Provides a transformation from a function to a Iterable-valued function that is equivalent to it. + * The first-class Kleisli arrow for Iterables. + * + * @return A transformation from a function to the equivalent Iterable-valued function. + */ + public static F, F>> arrow() { + return new F, F>>() { + public F> f(final F f) { + return iterable(f); + } + }; + } + + /** + * Binds the given function across the wrapped Iterable with a final join. + * + * @param f A function to bind across the Iterable. + * @return an iterable result of binding the given function over the wrapped Iterable. + */ + public > IterableW bind(final F f) { + return wrap(iterableStream(this).bind(new F>() { + public Stream f(final A a) { + return iterableStream(f.f(a)); + } + })); + } + + /** + * Performs function application within an iterable (applicative functor pattern). + * + * @param f The iterable function to apply. + * @return A new iterable after applying the given iterable function to the wrapped iterable. + */ + public IterableW apply(final Iterable> f) { + return wrap(f).bind(new F, Iterable>() { + public Iterable f(final F f) { + return map(f); + } + }); + } + + /** + * Binds the given function to the values in the given iterables with a final join. + * + * @param a A given iterable to bind the given function with. + * @param b A given iterable to bind the given function with. + * @param f The function to apply to the values in the given iterables. + * @return A new iterable after performing the map, then final join. + */ + public static IterableW bind(final Iterable a, final Iterable b, final F> f) { + return wrap(b).apply(wrap(a).map(f)); + } + + /** + * Promotes a function of arity-2 to a function on iterables. + * + * @param f The function to promote. + * @return A function of arity-2 promoted to map over iterables. + */ + public static F, F, IterableW>> liftM2(final F> f) { + return curry(new F2, Iterable, IterableW>() { + public IterableW f(final Iterable ca, final Iterable cb) { + return bind(ca, cb, f); + } + }); + } + + /** + * Performs a bind across each element of all iterables of an iterable, collecting the values in an iterable. + * This implementation is strict and requires O(n) stack space. + * + * @param as The iterable of iterables to transform. + * @return A iterable of iterables containing the results of the bind operations across all given iterables. + */ + public static > IterableW> sequence(final Iterable as) { + final Stream ts = iterableStream(as); + return ts.isEmpty() ? iterable(wrap(Option.none())) : wrap(ts.head()).bind(new F>>() { + public Iterable> f(final A a) { + return sequence(ts.tail().map(IterableW.>wrap())._1()) + .bind(new F, Iterable>>() { + public Iterable> f(final IterableW as) { + return iterable(wrap(Stream.cons(a, new P1>() { + public Stream _1() { + return iterableStream(as); + } + }))); + } + }); + } + }); + } + + /** + * The first-class bind function over Iterable. + * Returns a function that binds a given function across a given iterable. + * + * @return a function that binds a given function across a given iterable. + */ + public static > F, F, IterableW>> bind() { + return new F, F, IterableW>>() { + public F, IterableW> f(final IterableW a) { + return new F, IterableW>() { + public IterableW f(final F f) { + return a.bind(f); + } + }; + } + }; + } + + /** + * Joins an Iterable of Iterables into a single Iterable. + * + * @param as An Iterable of Iterables to join. + * @return the joined Iterable. + */ + public static > IterableW join(final Iterable as) { + final F id = identity(); + return wrap(as).bind(id); + } + + /** + * Returns a function that joins an Iterable of Iterables into a single Iterable. + * + * @return a function that joins an Iterable of Iterables into a single Iterable. + */ + public static > F, IterableW> join() { + return new F, IterableW>() { + public IterableW f(final Iterable a) { + return join(a); + } + }; + } + + /** + * Maps a given function across the wrapped Iterable. + * + * @param f A function to map across the wrapped Iterable. + * @return An Iterable of the results of mapping the given function across the wrapped Iterable. + */ + public IterableW map(final F f) { + return bind(iterable(f)); + } + + /** + * Returns a function that promotes any function so that it operates on Iterables. + * + * @return a function that promotes any function so that it operates on Iterables. + */ + public static F, F, IterableW>> map() { + return new F, F, IterableW>>() { + public F, IterableW> f(final F f) { + return new F, IterableW>() { + public IterableW f(final IterableW a) { + return a.map(f); + } + }; + } + }; + } + + /** + * The catamorphism for Iterables, implemented as a left fold. + * + * @param f The function with which to fold the wrapped iterable. + * @param z The base case value of the destination type, applied first (leftmost) to the fold. + * @return The result of the catamorphism. + */ + public B foldLeft(final F> f, final B z) { + B p = z; + for (final A x : this) { + p = f.f(p).f(x); + } + return p; + } + + /** + * Takes the first 2 elements of the iterable and applies the function to them, + * then applies the function to the result and the third element and so on. + * + * @param f The function to apply on each element of the iterable. + * @return The final result after the left-fold reduction. + */ + public A foldLeft1(final F2 f) { + return foldLeft1(curry(f)); + } + + /** + * Takes the first 2 elements of the iterable and applies the function to them, + * then applies the function to the result and the third element and so on. + * + * @param f The function to apply on each element of the iterable. + * @return The final result after the left-fold reduction. + */ + public A foldLeft1(final F> f) { + return iterableStream(this).foldLeft1(f); + } + + /** + * The catamorphism for Iterables, implemented as a right fold. + * + * @param f The function with which to fold the wrapped iterable. + * @param z The base case value of the destination type, applied last (rightmost) to the fold. + * @return The result of the catamorphism. + */ + public B foldRight(final F2 f, final B z) { + final F id = identity(); + return foldLeft(curry(new F3, A, B, B>() { + public B f(final F k, final A a, final B b) { + return k.f(f.f(a, b)); + } + }), id).f(z); + } + + /** + * Returns an iterator for this iterable. + * + * @return an iterator for this iterable. + */ + public Iterator iterator() { + return i.iterator(); + } + + /** + * Zips this iterable with the given iterable of functions, applying each function in turn to the + * corresponding element in this iterable to produce a new iterable. The iteration is normalised + * so that it ends when one of the iterators is exhausted. + * + * @param fs The iterable of functions to apply to this iterable. + * @return A new iterable with the results of applying the functions to this iterable. + */ + public IterableW zapp(final Iterable> fs) { + return wrap(iterableStream(this).zapp(iterableStream(fs))); + } + + /** + * Zips this iterable with the given iterable using the given function to produce a new iterable. If + * this iterable and the given iterable have different lengths, then the longer iterable is normalised + * so this function never fails. + * + * @param bs The iterable to zip this iterable with. + * @param f The function to zip this iterable and the given iterable with. + * @return A new iterable with a length the same as the shortest of this iterable and the given + * iterable. + */ + public Iterable zipWith(final Iterable bs, final F> f) { + return wrap(iterableStream(this).zipWith(iterableStream(bs), f)); + } + + /** + * Zips this iterable with the given iterable using the given function to produce a new iterable. If + * this iterable and the given iterable have different lengths, then the longer iterable is normalised + * so this function never fails. + * + * @param bs The iterable to zip this iterable with. + * @param f The function to zip this iterable and the given iterable with. + * @return A new iterable with a length the same as the shortest of this iterable and the given + * iterable. + */ + public Iterable zipWith(final Iterable bs, final F2 f) { + return zipWith(bs, curry(f)); + } + + /** + * Zips this iterable with the given iterable to produce a iterable of pairs. If this iterable and the + * given iterable have different lengths, then the longer iterable is normalised so this function + * never fails. + * + * @param bs The iterable to zip this iterable with. + * @return A new iterable with a length the same as the shortest of this iterable and the given + * iterable. + */ + public Iterable> zip(final Iterable bs) { + return wrap(iterableStream(this).zip(iterableStream(bs))); + } + + /** + * Zips this iterable with the index of its element as a pair. + * + * @return A new iterable with the same length as this iterable. + */ + public Iterable> zipIndex() { + return wrap(iterableStream(this).zipIndex()); + } + + /** + * Returns a java.util.List implementation for this iterable. + * The returned list cannot be modified. + * + * @return An immutable implementation of java.util.List for this iterable. + */ + public List toStandardList() { + return new List() { + + public int size() { + return iterableStream(IterableW.this).length(); + } + + public boolean isEmpty() { + return iterableStream(IterableW.this).isEmpty(); + } + + @SuppressWarnings({"unchecked"}) + public boolean contains(final Object o) { + return iterableStream(IterableW.this).exists(Equal.anyEqual().eq((A) o)); + } + + public Iterator iterator() { + return IterableW.this.iterator(); + } + + public Object[] toArray() { + return Array.iterableArray(iterableStream(IterableW.this)).array(); + } + + @SuppressWarnings({"SuspiciousToArrayCall"}) + public T[] toArray(final T[] a) { + return iterableStream(IterableW.this).toCollection().toArray(a); + } + + public boolean add(final A a) { + return false; + } + + public boolean remove(final Object o) { + return false; + } + + public boolean containsAll(final Collection c) { + return iterableStream(IterableW.this).toCollection().containsAll(c); + } + + public boolean addAll(final Collection c) { + return false; + } + + public boolean addAll(final int index, final Collection c) { + return false; + } + + public boolean removeAll(final Collection c) { + return false; + } + + public boolean retainAll(final Collection c) { + return false; + } + + public void clear() { + throw new UnsupportedOperationException("Modifying an immutable List."); + } + + public A get(final int index) { + return iterableStream(IterableW.this).index(index); + } + + public A set(final int index, final A element) { + throw new UnsupportedOperationException("Modifying an immutable List."); + } + + public void add(final int index, final A element) { + throw new UnsupportedOperationException("Modifying an immutable List."); + } + + public A remove(final int index) { + throw new UnsupportedOperationException("Modifying an immutable List."); + } + + public int indexOf(final Object o) { + int i = -1; + for (final A a : IterableW.this) { + i++; + if (a.equals(o)) + return i; + } + return i; + } + + public int lastIndexOf(final Object o) { + int i = -1; + int last = -1; + for (final A a : IterableW.this) { + i++; + if (a.equals(o)) + last = i; + } + return last; + } + + public ListIterator listIterator() { + return toListIterator(toZipper()); + } + + public ListIterator listIterator(final int index) { + return toListIterator(toZipper().bind(Zipper.move().f(index))); + } + + public List subList(final int fromIndex, final int toIndex) { + return wrap(Stream.iterableStream(IterableW.this).drop(fromIndex).take(toIndex - fromIndex)).toStandardList(); + } + + private ListIterator toListIterator(final Option> z) { + return new ListIterator() { + + private Option> pz = z; + + public boolean hasNext() { + return pz.isSome() && !pz.some().atEnd(); + } + + public A next() { + if (pz.isSome()) + pz = pz.some().next(); + else throw new NoSuchElementException(); + if (pz.isSome()) + return pz.some().focus(); + else throw new NoSuchElementException(); + } + + public boolean hasPrevious() { + return pz.isSome() && !pz.some().atStart(); + } + + public A previous() { + pz = pz.some().previous(); + return pz.some().focus(); + } + + public int nextIndex() { + return pz.some().index() + (pz.some().atEnd() ? 0 : 1); + } + + public int previousIndex() { + return pz.some().index() - (pz.some().atStart() ? 0 : 1); + } + + public void remove() { + throw new UnsupportedOperationException("Remove on immutable ListIterator"); + } + + public void set(final A a) { + throw new UnsupportedOperationException("Set on immutable ListIterator"); + } + + public void add(final A a) { + throw new UnsupportedOperationException("Add on immutable ListIterator"); + } + }; + } + + }; + } + + public Option> toZipper() { + return Zipper.fromStream(iterableStream(this)); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Iteratee.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Iteratee.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,356 @@ +package fj.data; + +import fj.F; +import fj.F1Functions; +import fj.Function; +import fj.P; +import fj.P1; +import fj.P2; +import fj.Unit; + +/** + * + */ +public final class Iteratee { + + /** The input to an iteratee. */ + public static abstract class Input { + + Input() {} // sealed + + public abstract Z apply(final P1 empty, final P1> el, final P1 eof); + + /** Input that has no values available */ + public static final Input empty() { + return new Input() { + @Override + public Z apply(final P1 empty, final P1> el, final P1 eof) { + return empty._1(); + } + }; + } + + /** Input that is exhausted */ + public static final Input eof() { + return new Input() { + @Override + public Z apply(final P1 empty, final P1> el, final P1 eof) { + return eof._1(); + } + }; + } + + /** Input that has a value available */ + public static final Input el(final E element) { + return new Input() { + @Override + public Z apply(final P1 empty, final P1> el, final P1 eof) { + return el._1().f(element); + } + }; + } + } + + /** A pure iteratee computation which is either done or needs more input */ + public static abstract class IterV { + + IterV() {} // sealed + + /** A computation that takes an element from an input to yield a new computation */ + public static IterV cont(final F, IterV> f) { + return new IterV() { + @Override + public Z fold(final F>, Z> done, final F, IterV>, Z> cont) { + return cont.f(f); + } + }; + } + + public abstract Z fold(final F>, Z> done, final F, IterV>, Z> cont); + + /** A computation that has finished */ + public static IterV done(final A a, final Input i) { + final P2> p = P.p(a, i); + return new IterV() { + @Override + public Z fold(final F>, Z> done, final F, IterV>, Z> cont) { + return done.f(p); + } + }; + } + + public final A run() { + final F, Option> runCont = + new F, Option>() { + final F>, Option> done = F1Functions.andThen(P2.>__1(), Option.some_()); + final F, IterV>, Option> cont = Function.constant(Option.none()); + + @Override + public Option f(final IterV i) { + return i.fold(done, cont); + } + }; + final F>, A> done = P2.>__1(); + final F, IterV>, A> cont = + new F, IterV>, A>() { + @Override + public A f(final F, IterV> k) { + return runCont.f(k.f(Input.eof())).valueE("diverging iteratee"); //$NON-NLS-1$ + } + }; + return fold(done, cont); + } + + /** TODO more documentation */ + public final IterV bind(final F> f) { + final F>, IterV> done = + new F>, IterV>() { + @Override + public IterV f(final P2> xe) { + final Input e = xe._2(); + final F>, IterV> done = + new F>, IterV>() { + @Override + public IterV f(final P2> y_) { + final B y = y_._1(); + return done(y, e); + } + }; + final F, IterV>, IterV> cont = + new F, IterV>, IterV>() { + @Override + public IterV f(final F, IterV> k) { + return k.f(e); + } + }; + final A x = xe._1(); + return f.f(x).fold(done, cont); + } + }; + final F, IterV>, IterV> cont = + new F, IterV>, IterV>() { + @Override + public IterV f(final F, IterV> k) { + return cont(new F, IterV>() { + @Override + public IterV f(final Input e) { + return k.f(e).bind(f); + } + }); + } + }; + return this.fold(done, cont); + } + + /** An iteratee that counts and consumes the elements of the input */ + public static final IterV length() { + final F, IterV>> step = + new F, IterV>>() { + final F, IterV>> step = this; + + @Override + public F, IterV> f(final Integer acc) { + final P1> empty = + new P1>() { + @Override + public IterV _1() { + return cont(step.f(acc)); + } + }; + final P1>> el = + new P1>>() { + @Override + public F> _1() { + return P.p(cont(step.f(acc + 1))).constant(); + } + }; + final P1> eof = + new P1>() { + @Override + public IterV _1() { + return done(acc, Input.eof()); + } + }; + return new F, IterV>() { + @Override + public IterV f(final Input s) { + return s.apply(empty, el, eof); + } + }; + } + }; + return cont(step.f(0)); + } + + /** An iteratee that skips the first n elements of the input */ + public static final IterV drop(final int n) { + final F, IterV> step = + new F, IterV>() { + final F, IterV> step = this; + + final P1> empty = + new P1>() { + @Override + public IterV _1() { + return cont(step); + } + }; + final P1>> el = + new P1>>() { + @Override + public F> _1() { + return P.p(IterV.drop(n - 1)).constant(); + } + }; + final P1> eof = + new P1>() { + @Override + public IterV _1() { + return done(Unit.unit(), Input.eof()); + } + }; + + @Override + public IterV f(final Input s) { + return s.apply(empty, el, eof); + } + }; + return n == 0 + ? done(Unit.unit(), Input.empty()) + : cont(step); + } + + /** An iteratee that consumes the head of the input */ + public static final IterV> head() { + final F, IterV>> step = + new F, IterV>>() { + final F, IterV>> step = this; + + final P1>> empty = + new P1>>() { + @Override + public IterV> _1() { + return cont(step); + } + }; + final P1>>> el = + new P1>>>() { + @Override + public F>> _1() { + return new F>>() { + @Override + public IterV> f(final E e) { + return done(Option.some(e), Input.empty()); + } + }; + } + }; + final P1>> eof = + new P1>>() { + @Override + public IterV> _1() { + return done(Option.none(), Input.eof()); + } + }; + + @Override + public IterV> f(final Input s) { + return s.apply(empty, el, eof); + } + }; + return cont(step); + } + + /** An iteratee that returns the first element of the input */ + public static final IterV> peek() { + final F, IterV>> step = + new F, IterV>>() { + final F, IterV>> step = this; + + final P1>> empty = + new P1>>() { + @Override + public IterV> _1() { + return cont(step); + } + }; + final P1>>> el = + new P1>>>() { + @Override + public F>> _1() { + return new F>>() { + @Override + public IterV> f(final E e) { + return done(Option.some(e), Input.el(e)); + } + }; + } + }; + final P1>> eof = + new P1>>() { + @Override + public IterV> _1() { + return done(Option.none(), Input.eof()); + } + }; + + @Override + public IterV> f(final Input s) { + return s.apply(empty, el, eof); + } + }; + return cont(step); + } + + /** An iteratee that consumes the input elements and returns them as a list in reverse order, + * so that the last line is the first element. This allows to build a list from 2 iteratees. */ + public static final IterV> list() { + final F, F, IterV>>> step = + new F, F, IterV>>>() { + final F, F, IterV>>> step = this; + + @Override + public F, IterV>> f(final List acc) { + final P1>> empty = + new P1>>() { + @Override + public IterV> _1() { + return cont(step.f(acc)); + } + }; + final P1>>> el = + new P1>>>() { + @Override + public F>> _1() { + return new F>>() { + @Override + public IterV> f(final E e) { + return cont(step.f(acc.cons(e))); + } + }; + } + }; + final P1>> eof = + new P1>>() { + @Override + public IterV> _1() { + return done(acc, Input.eof()); + } + }; + return new F, IterV>>() { + @Override + public IterV> f(final Input s) { + return s.apply(empty, el, eof); + } + }; + } + }; + return cont(step.f(List. nil())); + } + } + + private Iteratee() { + throw new UnsupportedOperationException(); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Java.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Java.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,2144 @@ +package fj.data; + +import fj.F; +import static fj.P.p; + +import fj.Function; +import fj.P1; +import fj.P2; +import fj.function.Effect1; + +import static fj.data.List.list; +import static fj.data.Option.some; + +import java.util.Arrays; +import java.util.Collection; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.PriorityQueue; +import java.util.Stack; +import java.util.TreeSet; +import java.util.Vector; +import java.util.Iterator; +import java.util.NoSuchElementException; +import static java.util.EnumSet.copyOf; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Delayed; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.SynchronousQueue; + +/** + * Functions that convert between types from the core Java API. + * + * @version %build.number% + */ +public final class Java { + private Java() { + throw new UnsupportedOperationException(); + } + + // BEGIN List -> + + /** + * A function that converts lists to array lists. + * + * @return A function that converts lists to array lists. + */ + public static F, ArrayList> List_ArrayList() { + return new F, ArrayList>() { + public ArrayList f(final List as) { + return new ArrayList(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to bit sets. + */ + public static final F, BitSet> List_BitSet = new F, BitSet>() { + public BitSet f(final List bs) { + final BitSet s = new BitSet(bs.length()); + bs.zipIndex().foreachDoEffect(new Effect1>() { + public void f(final P2 bi) { + s.set(bi._2(), bi._1()); + } + }); + return s; + } + }; + + /** + * A function that converts lists to array enum sets. + * + * @return A function that converts lists to enum sets. + */ + public static > F, EnumSet> List_EnumSet() { + return new F, EnumSet>() { + public EnumSet f(final List as) { + return copyOf(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to hash sets. + * + * @return A function that converts lists to hash sets. + */ + public static F, HashSet> List_HashSet() { + return new F, HashSet>() { + public HashSet f(final List as) { + return new HashSet(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to linked hash sets. + * + * @return A function that converts lists to linked hash sets. + */ + public static F, LinkedHashSet> List_LinkedHashSet() { + return new F, LinkedHashSet>() { + public LinkedHashSet f(final List as) { + return new LinkedHashSet(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to linked lists. + * + * @return A function that converts lists to linked lists. + */ + public static F, LinkedList> List_LinkedList() { + return new F, LinkedList>() { + public LinkedList f(final List as) { + return new LinkedList(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to priority queues. + * + * @return A function that converts lists to priority queues. + */ + public static F, PriorityQueue> List_PriorityQueue() { + return new F, PriorityQueue>() { + public PriorityQueue f(final List as) { + return new PriorityQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to stacks. + * + * @return A function that converts lists to stacks. + */ + public static F, Stack> List_Stack() { + return new F, Stack>() { + public Stack f(final List as) { + final Stack s = new Stack(); + s.addAll(as.toCollection()); + return s; + } + }; + } + + /** + * A function that converts lists to stacks. + * + * @return A function that converts lists to stacks. + */ + public static F, TreeSet> List_TreeSet() { + return new F, TreeSet>() { + public TreeSet f(final List as) { + return new TreeSet(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to vectors. + * + * @return A function that converts lists to vectors. + */ + public static F, Vector> List_Vector() { + return new F, Vector>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Vector f(final List as) { + return new Vector(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to array blocking queue. + * + * @param fair The argument to pass to the constructor of the array blocking queue. + * @return A function that converts lists to array blocking queue. + */ + public static F, ArrayBlockingQueue> List_ArrayBlockingQueue(final boolean fair) { + return new F, ArrayBlockingQueue>() { + public ArrayBlockingQueue f(final List as) { + return new ArrayBlockingQueue(as.length(), fair, as.toCollection()); + } + }; + } + + /** + * A function that converts lists to concurrent linked queues. + * + * @return A function that converts lists to concurrent linked queues. + */ + public static F, ConcurrentLinkedQueue> List_ConcurrentLinkedQueue() { + return new F, ConcurrentLinkedQueue>() { + public ConcurrentLinkedQueue f(final List as) { + return new ConcurrentLinkedQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to copy on write array lists. + * + * @return A function that converts lists to copy on write array lists. + */ + public static F, CopyOnWriteArrayList> List_CopyOnWriteArrayList() { + return new F, CopyOnWriteArrayList>() { + public CopyOnWriteArrayList f(final List as) { + return new CopyOnWriteArrayList(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to copy on write array sets. + * + * @return A function that converts lists to copy on write array sets. + */ + public static F, CopyOnWriteArraySet> List_CopyOnWriteArraySet() { + return new F, CopyOnWriteArraySet>() { + public CopyOnWriteArraySet f(final List as) { + return new CopyOnWriteArraySet(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to delay queues. + * + * @return A function that converts lists to delay queues. + */ + public static F, DelayQueue> List_DelayQueue() { + return new F, DelayQueue>() { + public DelayQueue f(final List as) { + return new DelayQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to linked blocking queues. + * + * @return A function that converts lists to linked blocking queues. + */ + public static F, LinkedBlockingQueue> List_LinkedBlockingQueue() { + return new F, LinkedBlockingQueue>() { + public LinkedBlockingQueue f(final List as) { + return new LinkedBlockingQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to priority blocking queues. + * + * @return A function that converts lists to priority blocking queues. + */ + public static F, PriorityBlockingQueue> List_PriorityBlockingQueue() { + return new F, PriorityBlockingQueue>() { + public PriorityBlockingQueue f(final List as) { + return new PriorityBlockingQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts lists to synchronous queues. + * + * @param fair The argument to pass to the constructor of the synchronous queue. + * @return A function that converts lists to synchronous queues. + */ + public static F, SynchronousQueue> List_SynchronousQueue(final boolean fair) { + return new F, SynchronousQueue>() { + public SynchronousQueue f(final List as) { + final SynchronousQueue q = new SynchronousQueue(fair); + q.addAll(as.toCollection()); + return q; + } + }; + } + + // END List -> + + // BEGIN Array -> + + /** + * A function that converts arrays to array lists. + * + * @return A function that converts arrays to array lists. + */ + public static F, ArrayList> Array_ArrayList() { + return new F, ArrayList>() { + public ArrayList f(final Array as) { + return new ArrayList(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to bit sets. + */ + public static final F, BitSet> Array_BitSet = new F, BitSet>() { + public BitSet f(final Array bs) { + final BitSet s = new BitSet(bs.length()); + + bs.zipIndex().foreachDoEffect(new Effect1>() { + public void f(final P2 bi) { + s.set(bi._2(), bi._1()); + } + }); + return s; + } + }; + + /** + * A function that converts arrays to enum sets. + * + * @return A function that converts arrays to enum sets. + */ + public static > F, EnumSet> Array_EnumSet() { + return new F, EnumSet>() { + public EnumSet f(final Array as) { + return copyOf(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to hash sets. + * + * @return A function that converts arrays to hash sets. + */ + public static F, HashSet> Array_HashSet() { + return new F, HashSet>() { + public HashSet f(final Array as) { + return new HashSet(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to linked hash sets. + * + * @return A function that converts arrays to linked hash sets. + */ + public static F, LinkedHashSet> Array_LinkedHashSet() { + return new F, LinkedHashSet>() { + public LinkedHashSet f(final Array as) { + return new LinkedHashSet(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to linked lists. + * + * @return A function that converts arrays to linked lists. + */ + public static F, LinkedList> Array_LinkedList() { + return new F, LinkedList>() { + public LinkedList f(final Array as) { + return new LinkedList(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to priority queues. + * + * @return A function that converts arrays to priority queues. + */ + public static F, PriorityQueue> Array_PriorityQueue() { + return new F, PriorityQueue>() { + public PriorityQueue f(final Array as) { + return new PriorityQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to stacks. + * + * @return A function that converts arrays to stacks. + */ + public static F, Stack> Array_Stack() { + return new F, Stack>() { + public Stack f(final Array as) { + final Stack s = new Stack(); + s.addAll(as.toCollection()); + return s; + } + }; + } + + /** + * A function that converts arrays to tree sets. + * + * @return A function that converts arrays to tree sets. + */ + public static F, TreeSet> Array_TreeSet() { + return new F, TreeSet>() { + public TreeSet f(final Array as) { + return new TreeSet(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to vectors. + * + * @return A function that converts arrays to vectors. + */ + public static F, Vector> Array_Vector() { + return new F, Vector>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Vector f(final Array as) { + return new Vector(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to array blocking queues. + * + * @param fair The argument to pass to the constructor of the array blocking queue. + * @return A function that converts arrays to array blocking queues. + */ + public static F, ArrayBlockingQueue> Array_ArrayBlockingQueue(final boolean fair) { + return new F, ArrayBlockingQueue>() { + public ArrayBlockingQueue f(final Array as) { + return new ArrayBlockingQueue(as.length(), fair, as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to concurrent linked queues. + * + * @return A function that converts arrays to concurrent linked queues. + */ + public static F, ConcurrentLinkedQueue> Array_ConcurrentLinkedQueue() { + return new F, ConcurrentLinkedQueue>() { + public ConcurrentLinkedQueue f(final Array as) { + return new ConcurrentLinkedQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to copy on write array lists. + * + * @return A function that converts arrays to copy on write array lists. + */ + public static F, CopyOnWriteArrayList> Array_CopyOnWriteArrayList() { + return new F, CopyOnWriteArrayList>() { + public CopyOnWriteArrayList f(final Array as) { + return new CopyOnWriteArrayList(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to copy on write array sets. + * + * @return A function that converts arrays to copy on write array sets. + */ + public static F, CopyOnWriteArraySet> Array_CopyOnWriteArraySet() { + return new F, CopyOnWriteArraySet>() { + public CopyOnWriteArraySet f(final Array as) { + return new CopyOnWriteArraySet(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to delay queues. + * + * @return A function that converts arrays to delay queues. + */ + public static F, DelayQueue> Array_DelayQueue() { + return new F, DelayQueue>() { + public DelayQueue f(final Array as) { + return new DelayQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to linked blocking queues. + * + * @return A function that converts arrays to linked blocking queues. + */ + public static F, LinkedBlockingQueue> Array_LinkedBlockingQueue() { + return new F, LinkedBlockingQueue>() { + public LinkedBlockingQueue f(final Array as) { + return new LinkedBlockingQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to priority blocking queues. + * + * @return A function that converts arrays to priority blocking queues. + */ + public static F, PriorityBlockingQueue> Array_PriorityBlockingQueue() { + return new F, PriorityBlockingQueue>() { + public PriorityBlockingQueue f(final Array as) { + return new PriorityBlockingQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts arrays to synchronous queues. + * + * @param fair The argument to pass to the constructor of the synchronous queue. + * @return A function that converts arrays to synchronous queues. + */ + public static F, SynchronousQueue> Array_SynchronousQueue(final boolean fair) { + return new F, SynchronousQueue>() { + public SynchronousQueue f(final Array as) { + final SynchronousQueue q = new SynchronousQueue(fair); + q.addAll(as.toCollection()); + return q; + } + }; + } + + // END Array -> + + // BEGIN Stream -> + + /** + * A function that converts streams to iterable. + * + * @return A function that converts streams to iterable. + */ + public static F, Iterable> Stream_Iterable() { + return new F, Iterable>() { + public Iterable f(final Stream as) { + return new Iterable() { + public Iterator iterator() { + return new Iterator() { + private Stream x = as; + + public boolean hasNext() { + return x.isNotEmpty(); + } + + public A next() { + if (x.isEmpty()) + throw new NoSuchElementException("Empty iterator"); + else { + final A a = x.head(); + x = x.tail()._1(); + return a; + } + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + }; + } + + /** + * A function that converts streams to array lists. + * + * @return A function that converts streams to array lists. + */ + public static F, ArrayList> Stream_ArrayList() { + return new F, ArrayList>() { + public ArrayList f(final Stream as) { + return new ArrayList(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to bit sets. + */ + public static final F, BitSet> Stream_BitSet = new F, BitSet>() { + public BitSet f(final Stream bs) { + final BitSet s = new BitSet(bs.length()); + bs.zipIndex().foreachDoEffect(new Effect1>() { + public void f(final P2 bi) { + s.set(bi._2(), bi._1()); + } + }); + return s; + } + }; + + /** + * A function that converts streams to enum sets. + * + * @return A function that converts streams to enum sets. + */ + public static > F, EnumSet> Stream_EnumSet() { + return new F, EnumSet>() { + public EnumSet f(final Stream as) { + return copyOf(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to hash sets. + * + * @return A function that converts streams to hash sets. + */ + public static F, HashSet> Stream_HashSet() { + return new F, HashSet>() { + public HashSet f(final Stream as) { + return new HashSet(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to linked hash sets. + * + * @return A function that converts streams to linked hash sets. + */ + public static F, LinkedHashSet> Stream_LinkedHashSet() { + return new F, LinkedHashSet>() { + public LinkedHashSet f(final Stream as) { + return new LinkedHashSet(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to linked lists. + * + * @return A function that converts streams to linked lists. + */ + public static F, LinkedList> Stream_LinkedList() { + return new F, LinkedList>() { + public LinkedList f(final Stream as) { + return new LinkedList(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to priority queues. + * + * @return A function that converts streams to priority queues. + */ + public static F, PriorityQueue> Stream_PriorityQueue() { + return new F, PriorityQueue>() { + public PriorityQueue f(final Stream as) { + return new PriorityQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to stacks. + * + * @return A function that converts streams to stacks. + */ + public static F, Stack> Stream_Stack() { + return new F, Stack>() { + public Stack f(final Stream as) { + final Stack s = new Stack(); + s.addAll(as.toCollection()); + return s; + } + }; + } + + /** + * A function that converts streams to tree sets. + * + * @return A function that converts streams to tree sets. + */ + public static F, TreeSet> Stream_TreeSet() { + return new F, TreeSet>() { + public TreeSet f(final Stream as) { + return new TreeSet(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to vectors. + * + * @return A function that converts streams to vectors. + */ + public static F, Vector> Stream_Vector() { + return new F, Vector>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Vector f(final Stream as) { + return new Vector(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to array blocking queues. + * + * @param fair The argument to pass to the constructor of the array blocking queue. + * @return A function that converts streams to array blocking queues. + */ + public static F, ArrayBlockingQueue> Stream_ArrayBlockingQueue(final boolean fair) { + return new F, ArrayBlockingQueue>() { + public ArrayBlockingQueue f(final Stream as) { + return new ArrayBlockingQueue(as.length(), fair, as.toCollection()); + } + }; + } + + /** + * A function that converts streams to concurrent linked queues. + * + * @return A function that converts streams to concurrent linked queues. + */ + public static F, ConcurrentLinkedQueue> Stream_ConcurrentLinkedQueue() { + return new F, ConcurrentLinkedQueue>() { + public ConcurrentLinkedQueue f(final Stream as) { + return new ConcurrentLinkedQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to copy on write array lists. + * + * @return A function that converts streams to copy on write array lists. + */ + public static F, CopyOnWriteArrayList> Stream_CopyOnWriteArrayList() { + return new F, CopyOnWriteArrayList>() { + public CopyOnWriteArrayList f(final Stream as) { + return new CopyOnWriteArrayList(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to copy on write array sets. + * + * @return A function that converts streams to copy on write array sets. + */ + public static F, CopyOnWriteArraySet> Stream_CopyOnWriteArraySet() { + return new F, CopyOnWriteArraySet>() { + public CopyOnWriteArraySet f(final Stream as) { + return new CopyOnWriteArraySet(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to delay queues. + * + * @return A function that converts streams to delay queues. + */ + public static F, DelayQueue> Stream_DelayQueue() { + return new F, DelayQueue>() { + public DelayQueue f(final Stream as) { + return new DelayQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to linked blocking queues. + * + * @return A function that converts streams to linked blocking queues. + */ + public static F, LinkedBlockingQueue> Stream_LinkedBlockingQueue() { + return new F, LinkedBlockingQueue>() { + public LinkedBlockingQueue f(final Stream as) { + return new LinkedBlockingQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to priority blocking queues. + * + * @return A function that converts streams to priority blocking queues. + */ + public static F, PriorityBlockingQueue> Stream_PriorityBlockingQueue() { + return new F, PriorityBlockingQueue>() { + public PriorityBlockingQueue f(final Stream as) { + return new PriorityBlockingQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts streams to synchronous queues. + * + * @param fair The argument to pass to the constructor of the synchronous queue. + * @return A function that converts streams to synchronous queues. + */ + public static F, SynchronousQueue> Stream_SynchronousQueue(final boolean fair) { + return new F, SynchronousQueue>() { + public SynchronousQueue f(final Stream as) { + final SynchronousQueue q = new SynchronousQueue(fair); + q.addAll(as.toCollection()); + return q; + } + }; + } + + // END Stream -> + + // BEGIN Option -> + + /** + * A function that converts options to array lists. + * + * @return A function that converts options to array lists. + */ + public static F, ArrayList> Option_ArrayList() { + return new F, ArrayList>() { + public ArrayList f(final Option as) { + return new ArrayList(as.toCollection()); + } + }; + } + + /** + * A function that converts options to bit sets. + */ + public static final F, BitSet> Option_BitSet = new F, BitSet>() { + public BitSet f(final Option bs) { + final BitSet s = new BitSet(bs.length()); + + bs.foreachDoEffect(new Effect1() { + public void f(final Boolean b) { + if (b) + s.set(0); + } + }); + return s; + } + }; + + /** + * A function that converts options to enum sets. + * + * @return A function that converts options to enum sets. + */ + public static > F, EnumSet> Option_EnumSet() { + return new F, EnumSet>() { + public EnumSet f(final Option as) { + return copyOf(as.toCollection()); + } + }; + } + + /** + * A function that converts options to hash sets. + * + * @return A function that converts options to hash sets. + */ + public static F, HashSet> Option_HashSet() { + return new F, HashSet>() { + public HashSet f(final Option as) { + return new HashSet(as.toCollection()); + } + }; + } + + /** + * A function that converts options to linked hash sets. + * + * @return A function that converts options to linked hash sets. + */ + public static F, LinkedHashSet> Option_LinkedHashSet() { + return new F, LinkedHashSet>() { + public LinkedHashSet f(final Option as) { + return new LinkedHashSet(as.toCollection()); + } + }; + } + + /** + * A function that converts options to linked lists. + * + * @return A function that converts options to linked lists. + */ + public static F, LinkedList> Option_LinkedList() { + return new F, LinkedList>() { + public LinkedList f(final Option as) { + return new LinkedList(as.toCollection()); + } + }; + } + + /** + * A function that converts options to priority queues. + * + * @return A function that converts options to priority queues. + */ + public static F, PriorityQueue> Option_PriorityQueue() { + return new F, PriorityQueue>() { + public PriorityQueue f(final Option as) { + return new PriorityQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts options to stacks. + * + * @return A function that converts options to stacks. + */ + public static F, Stack> Option_Stack() { + return new F, Stack>() { + public Stack f(final Option as) { + final Stack s = new Stack(); + s.addAll(as.toCollection()); + return s; + } + }; + } + + /** + * A function that converts options to tree sets. + * + * @return A function that converts options to tree sets. + */ + public static F, TreeSet> Option_TreeSet() { + return new F, TreeSet>() { + public TreeSet f(final Option as) { + return new TreeSet(as.toCollection()); + } + }; + } + + /** + * A function that converts options to vectors. + * + * @return A function that converts options to vectors. + */ + public static F, Vector> Option_Vector() { + return new F, Vector>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Vector f(final Option as) { + return new Vector(as.toCollection()); + } + }; + } + + /** + * A function that converts options to array blocking queues. + * + * @param fair The argument to pass to the constructor of the array blocking queue. + * @return A function that converts options to array blocking queues. + */ + public static F, ArrayBlockingQueue> Option_ArrayBlockingQueue(final boolean fair) { + return new F, ArrayBlockingQueue>() { + public ArrayBlockingQueue f(final Option as) { + return new ArrayBlockingQueue(as.length(), fair, as.toCollection()); + } + }; + } + + /** + * A function that converts options to concurrent linked queues. + * + * @return A function that converts options to concurrent linked queues. + */ + public static F, ConcurrentLinkedQueue> Option_ConcurrentLinkedQueue() { + return new F, ConcurrentLinkedQueue>() { + public ConcurrentLinkedQueue f(final Option as) { + return new ConcurrentLinkedQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts options to copy on write array lists. + * + * @return A function that converts options to copy on write array lists. + */ + public static F, CopyOnWriteArrayList> Option_CopyOnWriteArrayList() { + return new F, CopyOnWriteArrayList>() { + public CopyOnWriteArrayList f(final Option as) { + return new CopyOnWriteArrayList(as.toCollection()); + } + }; + } + + /** + * A function that converts options to copy on write array sets. + * + * @return A function that converts options to copy on write array sets. + */ + public static F, CopyOnWriteArraySet> Option_CopyOnWriteArraySet() { + return new F, CopyOnWriteArraySet>() { + public CopyOnWriteArraySet f(final Option as) { + return new CopyOnWriteArraySet(as.toCollection()); + } + }; + } + + /** + * A function that converts options to delay queues. + * + * @return A function that converts options to delay queues. + */ + public static F, DelayQueue> Option_DelayQueue() { + return new F, DelayQueue>() { + public DelayQueue f(final Option as) { + return new DelayQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts options to linked blocking queues. + * + * @return A function that converts options to linked blocking queues. + */ + public static F, LinkedBlockingQueue> Option_LinkedBlockingQueue() { + return new F, LinkedBlockingQueue>() { + public LinkedBlockingQueue f(final Option as) { + return new LinkedBlockingQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts options to priority blocking queues. + * + * @return A function that converts options to priority blocking queues. + */ + public static F, PriorityBlockingQueue> Option_PriorityBlockingQueue() { + return new F, PriorityBlockingQueue>() { + public PriorityBlockingQueue f(final Option as) { + return new PriorityBlockingQueue(as.toCollection()); + } + }; + } + + /** + * A function that converts options to synchronous queues. + * + * @param fair The argument to pass to the constructor of the synchronous queue. + * @return A function that converts options to synchronous queues. + */ + public static F, SynchronousQueue> Option_SynchronousQueue(final boolean fair) { + return new F, SynchronousQueue>() { + public SynchronousQueue f(final Option as) { + final SynchronousQueue q = new SynchronousQueue(fair); + q.addAll(as.toCollection()); + return q; + } + }; + } + + // END Option -> + + // BEGIN Either -> + + /** + * A function that converts eithers to array lists. + * + * @return A function that converts eithers to array lists. + */ + public static F, ArrayList> Either_ArrayListA() { + return Function.compose(Java.Option_ArrayList(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to array lists. + * + * @return A function that converts eithers to array lists. + */ + public static F, ArrayList> Either_ArrayListB() { + return Function.compose(Java.Option_ArrayList(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to bit sets. + * + * @return A function that converts eithers to bit sets. + */ + public static F, BitSet> Either_BitSetA() { + return Function.compose(Option_BitSet, Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to bit sets. + * + * @return A function that converts eithers to bit sets. + */ + public static F, BitSet> Either_BitSetB() { + return Function.compose(Option_BitSet, Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to enum sets. + * + * @return A function that converts eithers to enum sets. + */ + public static , B> F, EnumSet> Either_EnumSetA() { + return Function.compose(Java.Option_EnumSet(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to enum sets. + * + * @return A function that converts eithers to enum sets. + */ + public static > F, EnumSet> Either_EnumSetB() { + return Function.compose(Java.Option_EnumSet(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to hash sets. + * + * @return A function that converts eithers to hash sets. + */ + public static F, HashSet> Either_HashSetA() { + return Function.compose(Java.Option_HashSet(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to hash sets. + * + * @return A function that converts eithers to hash sets. + */ + public static F, HashSet> Either_HashSetB() { + return Function.compose(Java.Option_HashSet(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to linked hash sets. + * + * @return A function that converts eithers to linked hash sets. + */ + public static F, LinkedHashSet> Either_LinkedHashSetA() { + return Function.compose(Java.Option_LinkedHashSet(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to linked hash sets. + * + * @return A function that converts eithers to linked hash sets. + */ + public static F, LinkedHashSet> Either_LinkedHashSetB() { + return Function.compose(Java.Option_LinkedHashSet(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to linked lists. + * + * @return A function that converts eithers to linked lists. + */ + public static F, LinkedList> Either_LinkedListA() { + return Function.compose(Java.Option_LinkedList(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to priority queues. + * + * @return A function that eithers options to priority queues. + */ + public static F, PriorityQueue> Option_PriorityQueueA() { + return Function.compose(Java.Option_PriorityQueue(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to priority queues. + * + * @return A function that eithers options to priority queues. + */ + public static F, PriorityQueue> Option_PriorityQueueB() { + return Function.compose(Java.Option_PriorityQueue(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to linked lists. + * + * @return A function that converts eithers to linked lists. + */ + public static F, LinkedList> Either_LinkedListB() { + return Function.compose(Java.Option_LinkedList(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to stacks. + * + * @return A function that converts eithers to stacks. + */ + public static F, Stack> Either_StackA() { + return Function.compose(Java.Option_Stack(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to stacks. + * + * @return A function that converts eithers to stacks. + */ + public static F, Stack> Either_StackB() { + return Function.compose(Java.Option_Stack(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to tree sets. + * + * @return A function that converts eithers to tree sets. + */ + public static F, TreeSet> Either_TreeSetA() { + return Function.compose(Java.Option_TreeSet(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to tree sets. + * + * @return A function that converts eithers to tree sets. + */ + public static F, TreeSet> Either_TreeSetB() { + return Function.compose(Java.Option_TreeSet(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to vectors. + * + * @return A function that converts eithers to vectors. + */ + public static F, Vector> Either_VectorA() { + return Function.compose(Java.Option_Vector(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to vectors. + * + * @return A function that converts eithers to vectors. + */ + public static F, Vector> Either_VectorB() { + return Function.compose(Java.Option_Vector(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to array blocking queues. + * + * @param fair The argument to pass to the constructor of the array blocking queue. + * @return A function that converts eithers to array blocking queues. + */ + public static F, ArrayBlockingQueue> Either_ArrayBlockingQueueA(final boolean fair) { + return Function.compose(Java.Option_ArrayBlockingQueue(fair), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to array blocking queues. + * + * @param fair The argument to pass to the constructor of the array blocking queue. + * @return A function that converts eithers to array blocking queues. + */ + public static F, ArrayBlockingQueue> Either_ArrayBlockingQueueB(final boolean fair) { + return Function.compose(Java.Option_ArrayBlockingQueue(fair), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to concurrent linked queues. + * + * @return A function that converts eithers to concurrent linked queues. + */ + public static F, ConcurrentLinkedQueue> Either_ConcurrentLinkedQueueA() { + return Function.compose(Java.Option_ConcurrentLinkedQueue(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to concurrent linked queues. + * + * @return A function that converts eithers to concurrent linked queues. + */ + public static F, ConcurrentLinkedQueue> Either_ConcurrentLinkedQueueB() { + return Function.compose(Java.Option_ConcurrentLinkedQueue(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to copy on write array lists. + * + * @return A function that converts eithers to copy on write array lists. + */ + public static F, CopyOnWriteArrayList> Either_CopyOnWriteArrayListA() { + return Function.compose(Java.Option_CopyOnWriteArrayList(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to copy on write array lists. + * + * @return A function that converts eithers to copy on write array lists. + */ + public static F, CopyOnWriteArrayList> Either_CopyOnWriteArrayListB() { + return Function.compose(Java.Option_CopyOnWriteArrayList(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to copy on write array sets. + * + * @return A function that converts eithers to copy on write array sets. + */ + public static F, CopyOnWriteArraySet> Either_CopyOnWriteArraySetA() { + return Function.compose(Java.Option_CopyOnWriteArraySet(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to copy on write array sets. + * + * @return A function that converts eithers to copy on write array sets. + */ + public static F, CopyOnWriteArraySet> Either_CopyOnWriteArraySetB() { + return Function.compose(Java.Option_CopyOnWriteArraySet(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to delay queues. + * + * @return A function that converts eithers to delay queues. + */ + public static F, DelayQueue> Either_DelayQueueA() { + return Function.compose(Java.Option_DelayQueue(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to delay queues. + * + * @return A function that converts eithers to delay queues. + */ + public static F, DelayQueue> Either_DelayQueueB() { + return Function.compose(Java.Option_DelayQueue(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to linked blocking queues. + * + * @return A function that converts eithers to linked blocking queues. + */ + public static F, LinkedBlockingQueue> Either_LinkedBlockingQueueA() { + return Function.compose(Java.Option_LinkedBlockingQueue(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to linked blocking queues. + * + * @return A function that converts eithers to linked blocking queues. + */ + public static F, LinkedBlockingQueue> Either_LinkedBlockingQueueB() { + return Function.compose(Java.Option_LinkedBlockingQueue(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to priority blocking queues. + * + * @return A function that converts eithers to priority blocking queues. + */ + public static F, PriorityBlockingQueue> Either_PriorityBlockingQueueA() { + return Function.compose(Java.Option_PriorityBlockingQueue(), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to priority blocking queues. + * + * @return A function that converts eithers to priority blocking queues. + */ + public static F, PriorityBlockingQueue> Either_PriorityBlockingQueueB() { + return Function.compose(Java.Option_PriorityBlockingQueue(), Conversions.Either_OptionB()); + } + + /** + * A function that converts eithers to synchronous queues. + * + * @param fair The argument to pass to the constructor of the synchronous queue. + * @return A function that converts eithers to synchronous queues. + */ + public static F, SynchronousQueue> Either_SynchronousQueueA(final boolean fair) { + return Function.compose(Java.Option_SynchronousQueue(fair), Conversions.Either_OptionA()); + } + + /** + * A function that converts eithers to synchronous queues. + * + * @param fair The argument to pass to the constructor of the synchronous queue. + * @return A function that converts eithers to synchronous queues. + */ + public static F, SynchronousQueue> Either_SynchronousQueueB(final boolean fair) { + return Function.compose(Java.Option_SynchronousQueue(fair), Conversions.Either_OptionB()); + } + + // END Either -> + + // BEGIN String -> + + /** + * A function that converts strings to array lists. + */ + public static final F> String_ArrayList = + Function.compose(Java.List_ArrayList(), Conversions.String_List); + + /** + * A function that converts strings to hash sets. + */ + public static final F> String_HashSet = + Function.compose(Java.List_HashSet(), Conversions.String_List); + + /** + * A function that converts strings to linked hash sets. + */ + public static final F> String_LinkedHashSet = + Function.compose(Java.List_LinkedHashSet(), Conversions.String_List); + + /** + * A function that converts strings to linked lists. + */ + public static final F> String_LinkedList = + Function.compose(Java.List_LinkedList(), Conversions.String_List); + + /** + * A function that converts strings to priority queues. + */ + public static final F> String_PriorityQueue = + Function.compose(Java.List_PriorityQueue(), Conversions.String_List); + + /** + * A function that converts strings to stacks. + */ + public static final F> String_Stack = + Function.compose(Java.List_Stack(), Conversions.String_List); + + /** + * A function that converts strings to tree sets. + */ + public static final F> String_TreeSet = + Function.compose(Java.List_TreeSet(), Conversions.String_List); + + /** + * A function that converts strings to vectors. + */ + public static final F> String_Vector = + Function.compose(Java.List_Vector(), Conversions.String_List); + + /** + * A function that converts strings to array blocking queues. + * + * @param fair The argument to pass to the constructor of the array blocking queue. + * @return A function that converts strings to array blocking queues. + */ + public static F> String_ArrayBlockingQueue(final boolean fair) { + return Function.compose(Java.List_ArrayBlockingQueue(fair), Conversions.String_List); + } + + /** + * A function that converts strings to concurrent linked queues. + */ + public static final F> String_ConcurrentLinkedQueue = + Function.compose(Java.List_ConcurrentLinkedQueue(), Conversions.String_List); + + /** + * A function that converts strings to copy on write array lists. + */ + public static final F> String_CopyOnWriteArrayList = + Function.compose(Java.List_CopyOnWriteArrayList(), Conversions.String_List); + + /** + * A function that converts strings to copy on write array sets. + */ + public static final F> String_CopyOnWriteArraySet = + Function.compose(Java.List_CopyOnWriteArraySet(), Conversions.String_List); + + /** + * A function that converts strings to linked blocking queues. + */ + public static final F> String_LinkedBlockingQueue = + Function.compose(Java.List_LinkedBlockingQueue(), Conversions.String_List); + + /** + * A function that converts strings to priority blocking queues. + */ + public static final F> String_PriorityBlockingQueue = + Function.compose(Java.List_PriorityBlockingQueue(), Conversions.String_List); + + /** + * A function that converts strings to synchronous queues. + * + * @param fair The argument to pass to the constructor of the synchronous queue. + * @return A function that converts strings to synchronous queues. + */ + public static F> String_SynchronousQueue(final boolean fair) { + return Function.compose(Java.List_SynchronousQueue(fair), Conversions.String_List); + } + + // END String -> + + // BEGIN StringBuffer -> + + /** + * A function that converts string buffers to array lists. + */ + public static final F> StringBuffer_ArrayList = + Function.compose(Java.List_ArrayList(), Conversions.StringBuffer_List); + + /** + * A function that converts string buffers to hash sets. + */ + public static final F> StringBuffer_HashSet = + Function.compose(Java.List_HashSet(), Conversions.StringBuffer_List); + + /** + * A function that converts string buffers to linked hash sets. + */ + public static final F> StringBuffer_LinkedHashSet = + Function.compose(Java.List_LinkedHashSet(), Conversions.StringBuffer_List); + + /** + * A function that converts string buffers to linked lists. + */ + public static final F> StringBuffer_LinkedList = + Function.compose(Java.List_LinkedList(), Conversions.StringBuffer_List); + + /** + * A function that converts string buffers to priority queues. + */ + public static final F> StringBuffer_PriorityQueue = + Function.compose(Java.List_PriorityQueue(), Conversions.StringBuffer_List); + + /** + * A function that converts string buffers to stacks. + */ + public static final F> StringBuffer_Stack = + Function.compose(Java.List_Stack(), Conversions.StringBuffer_List); + + /** + * A function that converts string buffers to tree sets. + */ + public static final F> StringBuffer_TreeSet = + Function.compose(Java.List_TreeSet(), Conversions.StringBuffer_List); + + /** + * A function that converts string buffers to vectors. + */ + public static final F> StringBuffer_Vector = + Function.compose(Java.List_Vector(), Conversions.StringBuffer_List); + + /** + * A function that converts string buffers to array blocking queues. + * + * @param fair The argument to pass to the constructor of the array blocking queue. + * @return A function that converts string buffers to array blocking queues. + */ + public static F> StringBuffer_ArrayBlockingQueue(final boolean fair) { + return Function.compose(Java.List_ArrayBlockingQueue(fair), Conversions.StringBuffer_List); + } + + /** + * A function that converts string buffers to concurrent linked queues. + */ + public static final F> StringBuffer_ConcurrentLinkedQueue = + Function.compose(Java.List_ConcurrentLinkedQueue(), Conversions.StringBuffer_List); + + /** + * A function that converts string buffers to copy on write array lists. + */ + public static final F> StringBuffer_CopyOnWriteArrayList = + Function.compose(Java.List_CopyOnWriteArrayList(), Conversions.StringBuffer_List); + + /** + * A function that converts string buffers to copy on write array sets. + */ + public static final F> StringBuffer_CopyOnWriteArraySet = + Function.compose(Java.List_CopyOnWriteArraySet(), Conversions.StringBuffer_List); + + /** + * A function that converts string buffers to linked blocking queues. + */ + public static final F> StringBuffer_LinkedBlockingQueue = + Function.compose(Java.List_LinkedBlockingQueue(), Conversions.StringBuffer_List); + + /** + * A function that converts string buffers to priority blocking queues. + */ + public static final F> StringBuffer_PriorityBlockingQueue = + Function.compose(Java.List_PriorityBlockingQueue(), Conversions.StringBuffer_List); + + /** + * A function that converts string buffers to synchronous queues. + * + * @param fair The argument to pass to the constructor of the synchronous queue. + * @return A function that converts string buffers to synchronous queues. + */ + public static F> StringBuffer_SynchronousQueue(final boolean fair) { + return Function.compose(Java.List_SynchronousQueue(fair), Conversions.StringBuffer_List); + } + + // END StringBuffer -> + + // BEGIN StringBuilder -> + + /** + * A function that converts string builders to array lists. + */ + public static final F> StringBuilder_ArrayList = + Function.compose(Java.List_ArrayList(), Conversions.StringBuilder_List); + + /** + * A function that converts string builders to hash sets. + */ + public static final F> StringBuilder_HashSet = + Function.compose(Java.List_HashSet(), Conversions.StringBuilder_List); + + /** + * A function that converts string builders to linked hash sets. + */ + public static final F> StringBuilder_LinkedHashSet = + Function.compose(Java.List_LinkedHashSet(), Conversions.StringBuilder_List); + + /** + * A function that converts string builders to linked lists. + */ + public static final F> StringBuilder_LinkedList = + Function.compose(Java.List_LinkedList(), Conversions.StringBuilder_List); + + /** + * A function that converts string builders to priority queues. + */ + public static final F> StringBuilder_PriorityQueue = + Function.compose(Java.List_PriorityQueue(), Conversions.StringBuilder_List); + + /** + * A function that converts string builders to stacks. + */ + public static final F> StringBuilder_Stack = + Function.compose(Java.List_Stack(), Conversions.StringBuilder_List); + + /** + * A function that converts string builders to tree sets. + */ + public static final F> StringBuilder_TreeSet = + Function.compose(Java.List_TreeSet(), Conversions.StringBuilder_List); + + /** + * A function that converts string builders to vectors. + */ + public static final F> StringBuilder_Vector = + Function.compose(Java.List_Vector(), Conversions.StringBuilder_List); + + /** + * A function that converts string builders to array blocking queues. + * + * @param fair The argument to pass to the constructor of the array blocking queue. + * @return A function that converts string builders to array blocking queues. + */ + public static F> StringBuilder_ArrayBlockingQueue(final boolean fair) { + return Function.compose(Java.List_ArrayBlockingQueue(fair), Conversions.StringBuilder_List); + } + + /** + * A function that converts string builders to concurrent linked queues. + */ + public static final F> StringBuilder_ConcurrentLinkedQueue = + Function.compose(Java.List_ConcurrentLinkedQueue(), Conversions.StringBuilder_List); + + /** + * A function that converts string builders to copy on write array lists. + */ + public static final F> StringBuilder_CopyOnWriteArrayList = + Function.compose(Java.List_CopyOnWriteArrayList(), Conversions.StringBuilder_List); + + /** + * A function that converts string builders to copy on write array sets. + */ + public static final F> StringBuilder_CopyOnWriteArraySet = + Function.compose(Java.List_CopyOnWriteArraySet(), Conversions.StringBuilder_List); + + /** + * A function that converts string builders to linked blocking queues. + */ + public static final F> StringBuilder_LinkedBlockingQueue = + Function.compose(Java.List_LinkedBlockingQueue(), Conversions.StringBuilder_List); + + /** + * A function that converts string builders to priority blocking queues. + */ + public static final F> StringBuilder_PriorityBlockingQueue = + Function.compose(Java.List_PriorityBlockingQueue(), Conversions.StringBuilder_List); + + /** + * A function that converts string builders to synchronous queues. + * + * @param fair The argument to pass to the constructor of the synchronous queue. + * @return A function that converts string builders to synchronous queues. + */ + public static F> StringBuilder_SynchronousQueue(final boolean fair) { + return Function.compose(Java.List_SynchronousQueue(fair), Conversions.StringBuilder_List); + } + + // END StringBuffer -> + + // BEGIN ArrayList -> + + /** + * A function that converts array lists to lists. + * + * @return A function that converts array lists to lists. + */ + public static F, List> ArrayList_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final ArrayList as) { + return Collection_List(as); + } + }; + } + + // todo + + // END ArrayList -> + + /** + * A function that converts Java lists to lists. + * + * @return A function that converts Java lists to lists. + */ + public static F, List> JUList_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final java.util.List as) { + return Collection_List(as); + } + }; + } + + // BEGIN BitSet -> + + /** + * A function that converts bit sets to lists. + */ + public static final F> BitSet_List = new F>() { + public List f(final BitSet s) { + return List.unfold(new F>>() { + public Option> f(final Integer i) { + return i == s.length() ? + Option.>none() : + some(p(s.get(i), i + 1)); + } + }, 0); + } + }; + + // todo + + // END BitSet -> + + // BEGIN EnumSet -> + + /** + * A function that converts enum sets to lists. + * + * @return A function that converts enum sets to lists. + */ + public static > F, List> EnumSet_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final EnumSet as) { + return Collection_List(as); + } + }; + } + + public static List Collection_List(Collection c) { + return Java.Collection_List().f(c); + } + + public static F, List> Collection_List() { + return c -> list(c.toArray(array(c.size()))); + } + + @SafeVarargs + private static E[] array(int length, E... array) { + return Arrays.copyOf(array, length); + } + + // todo + + // END EnumSet -> + + // BEGIN HashSet -> + + /** + * A function that converts hash sets to lists. + * + * @return A function that converts hash sets to lists. + */ + public static F, List> HashSet_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final HashSet as) { + return Collection_List(as); + } + }; + } + + // todo + + // END HashSet -> + + // BEGIN LinkedHashSet -> + + /** + * A function that converts linked hash sets to lists. + * + * @return A function that converts linked hash sets to lists. + */ + public static F, List> LinkedHashSet_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final LinkedHashSet as) { + return Collection_List(as); + } + }; + } + + // todo + + // END LinkedHashSet -> + + // BEGIN Linked List -> + + /** + * A function that converts linked lists to lists. + * + * @return A function that converts linked lists to lists. + */ + public static F, List> LinkedList_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final LinkedList as) { + return Collection_List(as); + } + }; + } + + // todo + + // END Linked List -> + + // BEGIN PriorityQueue -> + + /** + * A function that converts priority queues to lists. + * + * @return A function that converts priority queues to lists. + */ + public static F, List> PriorityQueue_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final PriorityQueue as) { + return Collection_List(as); + } + }; + } + + // todo + + // END PriorityQueue -> + + // BEGIN Stack -> + + /** + * A function that converts stacks to lists. + * + * @return A function that converts stacks to lists. + */ + public static F, List> Stack_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final Stack as) { + return Collection_List(as); + } + }; + } + + // todo + + // END Stack -> + + // BEGIN TreeSet -> + + /** + * A function that converts tree sets to lists. + * + * @return A function that converts tree sets to lists. + */ + public static F, List> TreeSet_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final TreeSet as) { + return Collection_List(as); + } + }; + } + + // todo + + // END TreeSet -> + + // BEGIN Vector -> + + /** + * A function that converts vectors to lists. + * + * @return A function that converts vectors to lists. + */ + public static F, List> Vector_List() { + return new F, List>() { + @SuppressWarnings({"unchecked", "UseOfObsoleteCollectionType"}) + public List f(final Vector as) { + return Collection_List(as); + } + }; + } + + // todo + + // END Vector -> + + // BEGIN ArrayBlockingQueue -> + + /** + * A function that converts array blocking queues to lists. + * + * @return A function that converts array blocking queues to lists. + */ + public static F, List> ArrayBlockingQueue_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final ArrayBlockingQueue as) { + return Collection_List(as); + } + }; + } + + // todo + + // END ArrayBlockingQueue -> + + // BEGIN ConcurrentLinkedQueue -> + + /** + * A function that converts concurrent linked queues to lists. + * + * @return A function that converts concurrent linked queues to lists. + */ + public static F, List> ConcurrentLinkedQueue_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final ConcurrentLinkedQueue as) { + return Collection_List(as); + } + }; + } + + // todo + + // END ConcurrentLinkedQueue -> + + // BEGIN CopyOnWriteArrayList -> + + /** + * A function that converts copy on write array lists to lists. + * + * @return A function that converts copy on write array lists to lists. + */ + public static F, List> CopyOnWriteArrayList_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final CopyOnWriteArrayList as) { + return Collection_List(as); + } + }; + } + + // todo + + // END CopyOnWriteArrayList -> + + // BEGIN CopyOnWriteArraySet -> + + /** + * A function that converts copy on write array sets to lists. + * + * @return A function that converts copy on write array sets to lists. + */ + public static F, List> CopyOnWriteArraySet_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final CopyOnWriteArraySet as) { + return Collection_List(as); + } + }; + } + + // todo + + // END CopyOnWriteArraySet -> + + // BEGIN DelayQueue -> + + /** + * A function that converts delay queues to lists. + * + * @return A function that converts delay queues to lists. + */ + public static F, List> DelayQueue_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final DelayQueue as) { + return Collection_List(as); + } + }; + } + + // todo + + // END DelayQueue -> + + // BEGIN LinkedBlockingQueue -> + + /** + * A function that converts linked blocking queues to lists. + * + * @return A function that converts linked blocking queues to lists. + */ + public static F, List> LinkedBlockingQueue_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final LinkedBlockingQueue as) { + return Collection_List(as); + } + }; + } + + // todo + + // END LinkedBlockingQueue -> + + // BEGIN PriorityBlockingQueue -> + + /** + * A function that converts priority blocking queues to lists. + * + * @return A function that converts priority blocking queues to lists. + */ + public static F, List> PriorityBlockingQueue_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final PriorityBlockingQueue as) { + return Collection_List(as); + } + }; + } + + // todo + + // END PriorityBlockingQueue -> + + // BEGIN SynchronousQueue -> + + /** + * A function that converts synchronous queues to lists. + * + * @return A function that converts synchronous queues to lists. + */ + public static F, List> SynchronousQueue_List() { + return new F, List>() { + @SuppressWarnings({"unchecked"}) + public List f(final SynchronousQueue as) { + return Collection_List(as); + } + }; + } + + // todo + + // END SynchronousQueue -> + + // BEGIN Callable -> + + public static F, Callable> P1_Callable() { + return new F, Callable>() { + public Callable f(final P1 a) { + return new Callable() { + public A call() { + return a._1(); + } + }; + } + }; + } + +// END Callable -> + +// BEGIN Future -> + + public static F, P1>> Future_P1() { + return new F, P1>>() { + public P1> f(final Future a) { + return new P1>() { + @SuppressWarnings({"OverlyBroadCatchBlock"}) + public Either _1() { + Either r; + try { + r = Either.right(a.get()); + } + catch (Exception e) { + r = Either.left(e); + } + return r; + } + }; + } + }; + } + + // END Future -> +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/LazyString.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/LazyString.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,341 @@ +package fj.data; + +import fj.Equal; +import fj.F; +import fj.F2; +import static fj.Function.compose; +import static fj.Function.curry; +import static fj.P.p; +import fj.P1; +import fj.P2; +import static fj.data.Option.none; +import static fj.data.Option.some; +import static fj.data.Stream.join; +import static fj.function.Booleans.or; +import static fj.function.Characters.isSpaceChar; +import static fj.Equal.charEqual; +import static fj.Equal.streamEqual; + +import java.util.regex.Pattern; + +/** + * A lazy (non-evaluated) immutable character string. + */ +public final class LazyString implements CharSequence { + private final Stream s; + + private LazyString(final Stream s) { + this.s = s; + } + + /** + * Constructs a lazy string from a String. + * + * @param s A string from which to construct a lazy string. + * @return A lazy string with the characters from the given string. + */ + public static LazyString str(final String s) { + return new LazyString(Stream.unfold(new F, Option>>>() { + public Option>> f(final P2 o) { + final String s = o._1(); + final int n = o._2(); + final Option>> none = none(); + return s.length() <= n ? none : some(p(s.charAt(n), p(s, n + 1))); + } + }, p(s, 0))); + } + + /** + * The empty string. + */ + public static final LazyString empty = str(""); + + /** + * Constructs a lazy string from a stream of characters. + * + * @param s A stream of characters. + * @return A lazy string with the characters from the given stream. + */ + public static LazyString fromStream(final Stream s) { + return new LazyString(s); + } + + /** + * Gives a stream representation of this lazy string. + * + * @return A stream representation of this lazy string. + */ + public Stream toStream() { + return s; + } + + /** + * The length of the lazy string. Note that this operation is O(n). + * + * @return The length of this lazy string. + */ + public int length() { + return s.length(); + } + + /** + * Returns the caracter at the specified index. + * + * @param index The index for the character to be returned. + * @return The character at the specified index. + */ + public char charAt(final int index) { + return s.index(index); + } + + /** + * Gets the specified subsequence of this lazy string. + * This operation does not fail for indexes that are out of bounds. If the start index is past the end + * of this lazy string, then the resulting character sequence will be empty. If the end index is past the + * end of this lazy string, then the resulting character sequence will be truncated. + * + * @param start The character index of this lazy string at which to start the subsequence. + * @param end The character index of this lazy string at which to end the subsequence. + * @return A character sequence containing the specified character subsequence. + */ + public CharSequence subSequence(final int start, final int end) { + return fromStream(s.drop(start).take(end - start)); + } + + /** + * Returns the String representation of this lazy string. + * + * @return The String representation of this lazy string. + */ + public String toString() { + return new StringBuilder(this).toString(); + } + + /** + * Appends the given lazy string to the end of this lazy string. + * + * @param cs A lazy string to append to this one. + * @return A new lazy string that is the concatenation of this string and the given string. + */ + public LazyString append(final LazyString cs) { + return fromStream(s.append(cs.s)); + } + + /** + * Appends the given String to the end of this lazy string. + * + * @param s A String to append to this lazy string. + * @return A new lazy string that is the concatenation of this lazy string and the given string. + */ + public LazyString append(final String s) { + return append(str(s)); + } + + /** + * Returns true if the given lazy string is a substring of this lazy string. + * + * @param cs A substring to find in this lazy string. + * @return True if the given string is a substring of this string, otherwise False. + */ + public boolean contains(final LazyString cs) { + return or(s.tails().map(compose(startsWith().f(cs), fromStream))); + } + + /** + * Returns true if the given lazy string is a suffix of this lazy string. + * + * @param cs A string to find at the end of this lazy string. + * @return True if the given string is a suffix of this lazy string, otherwise False. + */ + public boolean endsWith(final LazyString cs) { + return reverse().startsWith(cs.reverse()); + } + + /** + * Returns true if the given lazy string is a prefix of this lazy string. + * + * @param cs A string to find at the start of this lazy string. + * @return True if the given string is a prefix of this lazy string, otherwise False. + */ + public boolean startsWith(final LazyString cs) { + return cs.isEmpty() || !isEmpty() && charEqual.eq(head(), cs.head()) && tail().startsWith(cs.tail()); + } + + + /** + * First-class prefix check. + * + * @return A function that yields true if the first argument is a prefix of the second. + */ + public static F> startsWith() { + return curry(new F2() { + public Boolean f(final LazyString needle, final LazyString haystack) { + return haystack.startsWith(needle); + } + }); + } + + /** + * Returns the first character of this string. + * + * @return The first character of this string, or error if the string is empty. + */ + public char head() { + return s.head(); + } + + /** + * Returns all but the first character of this string. + * + * @return All but the first character of this string, or error if the string is empty. + */ + public LazyString tail() { + return fromStream(s.tail()._1()); + } + + /** + * Checks if this string is empty. + * + * @return True if there are no characters in this string, otherwise False. + */ + public boolean isEmpty() { + return s.isEmpty(); + } + + /** + * Returns the reverse of this string. + * + * @return the reverse of this string. + */ + public LazyString reverse() { + return fromStream(s.reverse()); + } + + /** + * Returns the first index of the given character in this lazy string, if present. + * + * @param c A character to find in this lazy string. + * @return The first index of the given character in this lazy string, or None if the character is not present. + */ + public Option indexOf(final char c) { + return s.indexOf(Equal.charEqual.eq(c)); + } + + /** + * Returns the first index of the given substring in this lazy string, if present. + * + * @param cs A substring to find in this lazy string. + * @return The first index of the given substring in this lazy string, or None if there is no such substring. + */ + public Option indexOf(final LazyString cs) { + return s.substreams().indexOf(eqS.eq(cs.s)); + } + + /** + * Regular expression pattern matching. + * + * @param regex A regular expression to match this lazy string. + * @return True if this string mathches the given regular expression, otherwise False. + */ + public boolean matches(final String regex) { + return Pattern.matches(regex, this); + } + + /** + * Splits this lazy string by characters matching the given predicate. + * + * @param p A predicate that matches characters to be considered delimiters. + * @return A stream of the substrings in this lazy string, when separated by the given predicate. + */ + public Stream split(final F p) { + final Stream findIt = s.dropWhile(p); + final P2, Stream> ws = findIt.split(p); + return findIt.isEmpty() ? Stream.nil() + : Stream.cons(fromStream(ws._1()), new P1>() { + public Stream _1() { + return fromStream(ws._2()).split(p); + } + }); + } + + /** + * Splits this lazy string by the given delimiter character. + * + * @param c A delimiter character at which to split. + * @return A stream of substrings of this lazy string, when separated by the given delimiter. + */ + public Stream split(final char c) { + return split(charEqual.eq(c)); + } + + /** + * Splits this lazy string into words by spaces. + * + * @return A stream of the words in this lazy string, when split by spaces. + */ + public Stream words() { + return split(isSpaceChar); + } + + /** + * Splits this lazy string into lines. + * + * @return A stream of the lines in this lazy string, when split by newlines. + */ + public Stream lines() { + return split('\n'); + } + + /** + * Joins the given stream of lazy strings into one, separated by newlines. + * + * @param str A stream of lazy strings to join by newlines. + * @return A new lazy string, consisting of the given strings separated by newlines. + */ + public static LazyString unlines(final Stream str) { + return fromStream(join(str.intersperse(str("\n")).map(toStream))); + } + + /** + * Joins the given stream of lazy strings into one, separated by spaces. + * + * @param str A stream of lazy strings to join by spaces. + * @return A new lazy string, consisting of the given strings with spaces in between. + */ + public static LazyString unwords(final Stream str) { + return fromStream(join(str.intersperse(str(" ")).map(toStream))); + } + + /** + * First-class conversion from lazy strings to streams. + */ + public static final F> toStream = + new F>() { + public Stream f(final LazyString string) { + return string.toStream(); + } + }; + + /** + * First-class conversion from lazy strings to String. + */ + public static final F toString = + new F() { + public String f(final LazyString string) { + return string.toString(); + } + }; + + /** + * First-class conversion from character streams to lazy strings. + */ + public static final F, LazyString> fromStream = + new F, LazyString>() { + public LazyString f(final Stream s) { + return fromStream(s); + } + }; + + private static final Equal> eqS = streamEqual(charEqual); + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/List.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/List.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,2016 @@ +package fj.data; + +import static fj.Bottom.error; +import fj.F2Functions; +import fj.Equal; +import fj.F; +import fj.F2; +import fj.F3; +import fj.Function; +import fj.Hash; +import fj.Monoid; +import fj.Ord; +import fj.P; +import fj.P1; +import fj.P2; +import fj.Show; +import fj.Unit; +import static fj.Function.curry; +import static fj.Function.constant; +import static fj.Function.identity; +import static fj.Function.compose; +import static fj.P.p; +import static fj.P.p2; +import static fj.Unit.unit; +import static fj.data.Array.mkArray; +import static fj.data.List.Buffer.*; +import static fj.data.Option.none; +import static fj.data.Option.some; +import static fj.function.Booleans.not; +import static fj.Ordering.GT; +import static fj.Ord.intOrd; + +import fj.Ordering; +import fj.control.Trampoline; +import fj.function.Effect1; + +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Provides an in-memory, immutable, singly linked list. + * + * @version %build.number% + */ +public abstract class List implements Iterable { + private List() { + + } + + /** + * Returns an iterator for this list. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this list. + */ + public final Iterator iterator() { + return toCollection().iterator(); + } + + /** + * The first element of the linked list or fails for the empty list. + * + * @return The first element of the linked list or fails for the empty list. + */ + public abstract A head(); + + /** + * The list without the first element or fails for the empty list. + * + * @return The list without the first element or fails for the empty list. + */ + public abstract List tail(); + + /** + * The length of this list. + * + * @return The length of this list. + */ + public final int length() { + return foldLeft(new F>() { + public F f(final Integer i) { + return new F() { + public Integer f(final A a) { + return i + 1; + } + }; + } + }, 0); + } + + /** + * Returns true if this list is empty, false otherwise. + * + * @return true if this list is empty, false otherwise. + */ + public final boolean isEmpty() { + return this instanceof Nil; + } + + /** + * Returns false if this list is empty, true otherwise. + * + * @return false if this list is empty, true otherwise. + */ + public final boolean isNotEmpty() { + return this instanceof Cons; + } + + /** + * Performs a reduction on this list using the given arguments. + * + * @param nil The value to return if this list is empty. + * @param cons The function to apply to the head and tail of this list if it is not empty. + * @return A reduction on this list. + */ + public final B list(final B nil, final F, B>> cons) { + return isEmpty() ? nil : cons.f(head()).f(tail()); + } + + /** + * Returns the head of this list if there is one or the given argument if this list is empty. + * + * @param a The argument to return if this list is empty. + * @return The head of this list if there is one or the given argument if this list is empty. + */ + public final A orHead(final P1 a) { + return isEmpty() ? a._1() : head(); + } + + /** + * Returns the tail of this list if there is one or the given argument if this list is empty. + * + * @param as The argument to return if this list is empty. + * @return The tail of this list if there is one or the given argument if this list is empty. + */ + public final List orTail(final P1> as) { + return isEmpty() ? as._1() : tail(); + } + + /** + * Returns an option projection of this list; None if empty, or the first element in + * Some. + * + * @return An option projection of this list. + */ + public final Option toOption() { + return isEmpty() ? Option.none() : some(head()); + } + + /** + * Returns an either projection of this list; the given argument in Left if empty, or + * the first element in Right. + * + * @param x The value to return in left if this list is empty. + * @return An either projection of this list. + */ + public final Either toEither(final P1 x) { + return isEmpty() ? Either.left(x._1()) : Either.right(head()); + } + + /** + * Returns a stream projection of this list. + * + * @return A stream projection of this list. + */ + public final Stream toStream() { + final Stream nil = Stream.nil(); + return foldRight(new F, Stream>>() { + public F, Stream> f(final A a) { + return new F, Stream>() { + public Stream f(final Stream as) { + return as.cons(a); + } + }; + } + }, nil); + } + + /** + * Returns a array projection of this list. + * + * @return A array projection of this list. + */ + @SuppressWarnings({"unchecked"}) + public final Array toArray() { + final Object[] a = new Object[length()]; + List x = this; + for (int i = 0; i < length(); i++) { + a[i] = x.head(); + x = x.tail(); + } + + return mkArray(a); + } + + /** + * Returns a array projection of this list. + * + * @param c The class type of the array to return. + * @return A array projection of this list. + */ + @SuppressWarnings({"unchecked", "UnnecessaryFullyQualifiedName"}) + public final Array toArray(final Class c) { + final A[] a = (A[]) java.lang.reflect.Array.newInstance(c.getComponentType(), length()); + List x = this; + for (int i = 0; i < length(); i++) { + a[i] = x.head(); + x = x.tail(); + } + + return Array.array(a); + } + + /** + * Returns an array from this list. + * + * @param c The class type of the array to return. + * @return An array from this list. + */ + public final A[] array(final Class c) { + return toArray(c).array(c); + } + + /** + * Prepends (cons) the given element to this list to product a new list. + * + * @param a The element to prepend. + * @return A new list with the given element at the head. + */ + public final List cons(final A a) { + return new Cons(a, this); + } + + /** + * Prepends (cons) the given element to this list to product a new list. This method is added to prevent conflict with + * overloads. + * + * @param a The element to prepend. + * @return A new list with the given element at the head. + */ + public final List conss(final A a) { + return new Cons(a, this); + } + + /** + * Maps the given function across this list. + * + * @param f The function to map across this list. + * @return A new list after the given function has been applied to each element. + */ + public final List map(final F f) { + final Buffer bs = empty(); + + for (List xs = this; xs.isNotEmpty(); xs = xs.tail()) { + bs.snoc(f.f(xs.head())); + } + + return bs.toList(); + } + + /** + * Performs a side-effect for each element of this list. + * + * @param f The side-effect to perform for the given element. + * @return The unit value. + */ + public final Unit foreach(final F f) { + for (List xs = this; xs.isNotEmpty(); xs = xs.tail()) { + f.f(xs.head()); + } + + return unit(); + } + + /** + * Performs a side-effect for each element of this list. + * + * @param f The side-effect to perform for the given element. + */ + public final void foreachDoEffect(final Effect1 f) { + for (List xs = this; xs.isNotEmpty(); xs = xs.tail()) { + f.f(xs.head()); + } + } + + /** + * Filters elements from this list by returning only elements which produce true when + * the given function is applied to them. + * + * @param f The predicate function to filter on. + * @return A new list whose elements all match the given predicate. + */ + public final List filter(final F f) { + final Buffer b = empty(); + + for (List xs = this; xs.isNotEmpty(); xs = xs.tail()) { + final A h = xs.head(); + if (f.f(h)) { + b.snoc(h); + } + } + + return b.toList(); + } + + /** + * Filters elements from this list by returning only elements which produce false when + * the given function is applied to them. + * + * @param f The predicate function to filter on. + * @return A new list whose elements do not match the given predicate. + */ + public final List removeAll(final F f) { + return filter(compose(not, f)); + } + + /** + * Removes the first element that equals the given object. + * To remove all matches, use removeAll(e.eq(a)) + * + * @param a The element to remove + * @param e An Equals instance for the element's type. + * @return A new list whose elements do not match the given predicate. + */ + public final List delete(final A a, final Equal e) { + final P2, List> p = span(compose(not, e.eq(a))); + return p._2().isEmpty() ? p._1() : p._1().append(p._2().tail()); + } + + /** + * Returns the first elements of the head of this list that match the given predicate function. + * + * @param f The predicate function to apply on this list until it finds an element that does not + * hold, or the list is exhausted. + * @return The first elements of the head of this list that match the given predicate function. + */ + public final List takeWhile(final F f) { + final Buffer b = empty(); + boolean taking = true; + + for (List xs = this; xs.isNotEmpty() && taking; xs = xs.tail()) { + final A h = xs.head(); + if (f.f(h)) { + b.snoc(h); + } else { + taking = false; + } + } + + return b.toList(); + } + + /** + * Removes elements from the head of this list that do not match the given predicate function + * until an element is found that does match or the list is exhausted. + * + * @param f The predicate function to apply through this list. + * @return The list whose first element does not match the given predicate function. + */ + public final List dropWhile(final F f) { + List xs; + + //noinspection StatementWithEmptyBody + for (xs = this; xs.isNotEmpty() && f.f(xs.head()); xs = xs.tail()) ; + + return xs; + } + + /** + * Returns a tuple where the first element is the longest prefix of this list that satisfies + * the given predicate and the second element is the remainder of the list. + * + * @param p A predicate to be satisfied by a prefix of this list. + * @return A tuple where the first element is the longest prefix of this list that satisfies + * the given predicate and the second element is the remainder of the list. + */ + public final P2, List> span(final F p) { + final Buffer b = empty(); + for (List xs = this; xs.isNotEmpty(); xs = xs.tail()) { + if (p.f(xs.head())) + b.snoc(xs.head()); + else + return P.p(b.toList(), xs); + } + return P.p(b.toList(), List.nil()); + } + + /** + * Returns a tuple where the first element is the longest prefix of this list that does not satisfy + * the given predicate and the second element is the remainder of the list. + * + * @param p A predicate for an element to not satisfy by a prefix of this list. + * @return A tuple where the first element is the longest prefix of this list that does not satisfy + * the given predicate and the second element is the remainder of the list. + */ + public final P2, List> breakk(final F p) { + return span(new F() { + public Boolean f(final A a) { + return !p.f(a); + } + }); + } + + /** + * Groups elements according to the given equality implementation by longest + * sequence of equal elements. + * + * @param e The equality implementation for the elements. + * @return A list of grouped elements. + */ + public final List> group(final Equal e) { + if (isEmpty()) + return nil(); + else { + final P2, List> z = tail().span(e.eq(head())); + return cons(z._1().cons(head()), z._2().group(e)); + } + } + + + /** + * Binds the given function across each element of this list with a final join. + * + * @param f The function to apply to each element of this list. + * @return A new list after performing the map, then final join. + */ + public final List bind(final F> f) { + final Buffer b = empty(); + + for (List xs = this; xs.isNotEmpty(); xs = xs.tail()) { + b.append(f.f(xs.head())); + } + + return b.toList(); + } + + /** + * Binds the given function across each element of this list and the given list with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given list. + * @return A new list after performing the map, then final join. + */ + public final List bind(final List lb, final F> f) { + return lb.apply(map(f)); + } + + /** + * Binds the given function across each element of this list and the given list with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given list. + * @return A new list after performing the map, then final join. + */ + public final List bind(final List lb, final F2 f) { + return bind(lb, curry(f)); + } + + /** + * Promotes the given function of arity-2 to a function on lists. + * + * @param f The function to promote to a function on lists. + * @return The given function, promoted to operate on lists. + */ + public static F, F, List>> liftM2(final F> f) { + return curry(new F2, List, List>() { + public List f(final List as, final List bs) { + return as.bind(bs, f); + } + }); + } + + /** + * Binds the given function across each element of this list and the given lists with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param lc A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given lists. + * @return A new list after performing the map, then final join. + */ + public final List bind(final List lb, final List lc, final F>> f) { + return lc.apply(bind(lb, f)); + } + + /** + * Binds the given function across each element of this list and the given lists with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param lc A given list to bind the given function with. + * @param ld A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given lists. + * @return A new list after performing the map, then final join. + */ + public final List bind(final List lb, final List lc, final List ld, + final F>>> f) { + return ld.apply(bind(lb, lc, f)); + } + + /** + * Binds the given function across each element of this list and the given lists with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param lc A given list to bind the given function with. + * @param ld A given list to bind the given function with. + * @param le A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given lists. + * @return A new list after performing the map, then final join. + */ + public final List bind(final List lb, final List lc, final List ld, final List le, + final F>>>> f) { + return le.apply(bind(lb, lc, ld, f)); + } + + /** + * Binds the given function across each element of this list and the given lists with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param lc A given list to bind the given function with. + * @param ld A given list to bind the given function with. + * @param le A given list to bind the given function with. + * @param lf A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given lists. + * @return A new list after performing the map, then final join. + */ + public final List bind(final List lb, final List lc, final List ld, final List le, + final List lf, final F>>>>> f) { + return lf.apply(bind(lb, lc, ld, le, f)); + } + + /** + * Binds the given function across each element of this list and the given lists with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param lc A given list to bind the given function with. + * @param ld A given list to bind the given function with. + * @param le A given list to bind the given function with. + * @param lf A given list to bind the given function with. + * @param lg A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given lists. + * @return A new list after performing the map, then final join. + */ + public final List bind(final List lb, final List lc, final List ld, final List le, + final List lf, final List lg, + final F>>>>>> f) { + return lg.apply(bind(lb, lc, ld, le, lf, f)); + } + + /** + * Binds the given function across each element of this list and the given lists with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param lc A given list to bind the given function with. + * @param ld A given list to bind the given function with. + * @param le A given list to bind the given function with. + * @param lf A given list to bind the given function with. + * @param lg A given list to bind the given function with. + * @param lh A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given lists. + * @return A new list after performing the map, then final join. + */ + public final List bind(final List lb, final List lc, final List ld, final List le, + final List lf, final List lg, final List lh, + final F>>>>>>> f) { + return lh.apply(bind(lb, lc, ld, le, lf, lg, f)); + } + + /** + * Performs a bind across each list element, but ignores the element value each time. + * + * @param bs The list to apply in the final join. + * @return A new list after the final join. + */ + public final List sequence(final List bs) { + final F> c = constant(bs); + return bind(c); + } + + /** + * Performs function application within a list (applicative functor pattern). + * + * @param lf The list of functions to apply. + * @return A new list after applying the given list of functions through this list. + */ + public final List apply(final List> lf) { + return lf.bind(new F, List>() { + public List f(final F f) { + return map(f); + } + }); + } + + /** + * Appends the given list to this list. + * + * @param as The list to append to this one. + * @return A new list that has appended the given list. + */ + public final List append(final List as) { + return fromList(this).append(as).toList(); + } + + /** + * Performs a right-fold reduction across this list. This function uses O(length) stack space. + * + * @param f The function to apply on each element of the list. + * @param b The beginning value to start the application from. + * @return The final result after the right-fold reduction. + */ + public final B foldRight(final F> f, final B b) { + return isEmpty() ? b : f.f(head()).f(tail().foldRight(f, b)); + } + + /** + * Performs a right-fold reduction across this list. This function uses O(length) stack space. + * + * @param f The function to apply on each element of the list. + * @param b The beginning value to start the application from. + * @return The final result after the right-fold reduction. + */ + public final B foldRight(final F2 f, final B b) { + return foldRight(curry(f), b); + } + + /** + * Performs a right-fold reduction across this list in O(1) stack space. + * @param f The function to apply on each element of the list. + * @param b The beginning value to start the application from. + * @return A Trampoline containing the final result after the right-fold reduction. + */ + public final Trampoline foldRightC(final F2 f, final B b) { + return Trampoline.suspend(new P1>() { + public Trampoline _1() { + return isEmpty() ? Trampoline.pure(b) : tail().foldRightC(f, b).map(F2Functions.f(f, head())); + } + }); + } + + /** + * Performs a left-fold reduction across this list. This function runs in constant space. + * + * @param f The function to apply on each element of the list. + * @param b The beginning value to start the application from. + * @return The final result after the left-fold reduction. + */ + public final B foldLeft(final F> f, final B b) { + B x = b; + + for (List xs = this; !xs.isEmpty(); xs = xs.tail()) { + x = f.f(x).f(xs.head()); + } + + return x; + } + + /** + * Performs a left-fold reduction across this list. This function runs in constant space. + * + * @param f The function to apply on each element of the list. + * @param b The beginning value to start the application from. + * @return The final result after the left-fold reduction. + */ + public final B foldLeft(final F2 f, final B b) { + return foldLeft(curry(f), b); + } + + /** + * Takes the first 2 elements of the list and applies the function to them, + * then applies the function to the result and the third element and so on. + * + * @param f The function to apply on each element of the list. + * @return The final result after the left-fold reduction. + */ + public final A foldLeft1(final F2 f) { + return foldLeft1(curry(f)); + } + + /** + * Takes the first 2 elements of the list and applies the function to them, + * then applies the function to the result and the third element and so on. + * + * @param f The function to apply on each element of the list. + * @return The final result after the left-fold reduction. + */ + public final A foldLeft1(final F> f) { + if (isEmpty()) + throw error("Undefined: foldLeft1 on empty list"); + return tail().foldLeft(f, head()); + } + + /** + * Reverse this list in constant stack space. + * + * @return A new list that is the reverse of this one. + */ + public final List reverse() { + return foldLeft(new F, F>>() { + public F> f(final List as) { + return new F>() { + public List f(final A a) { + return cons(a, as); + } + }; + } + }, List.nil()); + } + + /** + * Returns the element at the given index if it exists, fails otherwise. + * + * @param i The index at which to get the element to return. + * @return The element at the given index if it exists, fails otherwise. + */ + public final A index(final int i) { + if (i < 0 || i > length() - 1) + throw error("index " + i + " out of range on list with length " + length()); + else { + List xs = this; + + for (int c = 0; c < i; c++) { + xs = xs.tail(); + } + + return xs.head(); + } + } + + /** + * Takes the given number of elements from the head of this list if they are available. + * + * @param i The maximum number of elements to take from this list. + * @return A new list with a length the same, or less than, this list. + */ + public final List take(final int i) { + return i <= 0 || isEmpty() ? List.nil() : cons(head(), tail().take(i - 1)); + } + + /** + * Drops the given number of elements from the head of this list if they are available. + * + * @param i The number of elements to drop from the head of this list. + * @return A list with a length the same, or less than, this list. + */ + public final List drop(final int i) { + int c = 0; + + List xs = this; + + for (; xs.isNotEmpty() && c < i; xs = xs.tail()) + c++; + + return xs; + } + + /** + * Splits this list into two lists at the given index. If the index goes out of bounds, then it is + * normalised so that this function never fails. + * + * @param i The index at which to split this list in two parts. + * @return A pair of lists split at the given index of this list. + */ + public final P2, List> splitAt(final int i) { + P2, List> s = p(List.nil(), List.nil()); + + int c = 0; + for (List xs = this; xs.isNotEmpty(); xs = xs.tail()) { + final A h = xs.head(); + s = c < i ? s.map1(new F, List>() { + public List f(final List as) { + return as.snoc(h); + } + }) : s.map2(new F, List>() { + public List f(final List as) { + return as.snoc(h); + } + }); + c++; + } + + return s; + } + + /** + * Splits this list into lists of the given size. If the size of this list is not evenly divisible by + * the given number, the last partition will contain the remainder. + * + * @param n The size of the partitions into which to split this list. + * @return A list of sublists of this list, of at most the given size. + */ + public final List> partition(final int n) { + if (n < 1) + throw error("Can't create list partitions shorter than 1 element long."); + if (isEmpty()) + throw error("Partition on empty list."); + return unfold(new F, Option, List>>>() { + public Option, List>> f(final List as) { + return as.isEmpty() ? Option., List>>none() : some(as.splitAt(n)); + } + }, this); + } + + /** + * Returns the list of initial segments of this list, shortest first. + * + * @return The list of initial segments of this list, shortest first. + */ + public final List> inits() { + List> s = single(List.nil()); + if (isNotEmpty()) + s = s.append(tail().inits().map(List.cons().f(head()))); + return s; + } + + /** + * Returns the list of final segments of this list, longest first. + * + * @return The list of final segments of this list, longest first. + */ + public final List> tails() { + return isEmpty() ? single(List.nil()) : cons(this, tail().tails()); + } + + /** + * Sorts this list using the given order over elements using a merge sort algorithm. + * + * @param o The order over the elements of this list. + * @return A sorted list according to the given order. + */ + public final List sort(final Ord o) { + if (isEmpty()) + return nil(); + else if (tail().isEmpty()) + return this; + else { + final class Merge { + List merge(List xs, List ys, final Ord o) { + final Buffer buf = empty(); + + while (true) { + if (xs.isEmpty()) { + buf.append(ys); + break; + } + + if (ys.isEmpty()) { + buf.append(xs); + break; + } + + final A x = xs.head(); + final A y = ys.head(); + + if (o.isLessThan(x, y)) { + buf.snoc(x); + xs = xs.tail(); + } else { + buf.snoc(y); + ys = ys.tail(); + } + } + + return buf.toList(); + } + } + + final P2, List> s = splitAt(length() / 2); + return new Merge().merge(s._1().sort(o), s._2().sort(o), o); + } + } + + /** + * Zips this list with the given list using the given function to produce a new list. If this list + * and the given list have different lengths, then the longer list is normalised so this function + * never fails. + * + * @param bs The list to zip this list with. + * @param f The function to zip this list and the given list with. + * @return A new list with a length the same as the shortest of this list and the given list. + */ + public final List zipWith(List bs, final F> f) { + final Buffer buf = empty(); + List as = this; + + while (as.isNotEmpty() && bs.isNotEmpty()) { + buf.snoc(f.f(as.head()).f(bs.head())); + as = as.tail(); + bs = bs.tail(); + } + + return buf.toList(); + } + + /** + * Zips this list with the given list using the given function to produce a new list. If this list + * and the given list have different lengths, then the longer list is normalised so this function + * never fails. + * + * @param bs The list to zip this list with. + * @param f The function to zip this list and the given list with. + * @return A new list with a length the same as the shortest of this list and the given list. + */ + public final List zipWith(final List bs, final F2 f) { + return zipWith(bs, curry(f)); + } + + /** + * Provides a first-class version of zipWith + * + * @return The first-class version of zipWith + */ + public static F, F, F>, List>>> zipWith() { + return curry(new F3, List, F>, List>() { + public List f(final List as, final List bs, final F> f) { + return as.zipWith(bs, f); + } + }); + } + + /** + * Zips this list with the given list to produce a list of pairs. If this list and the given list + * have different lengths, then the longer list is normalised so this function never fails. + * + * @param bs The list to zip this list with. + * @return A new list with a length the same as the shortest of this list and the given list. + */ + public final List> zip(final List bs) { + final F>> __2 = p2(); + return zipWith(bs, __2); + } + + /** + * The first-class version of the zip function. + * + * @return A function that zips the given lists to produce a list of pairs. + */ + public static F, F, List>>> zip() { + return curry(new F2, List, List>>() { + public List> f(final List as, final List bs) { + return as.zip(bs); + } + }); + } + + /** + * Zips this list with the index of its element as a pair. + * + * @return A new list with the same length as this list. + */ + public final List> zipIndex() { + return zipWith(range(0, length()), new F>>() { + public F> f(final A a) { + return new F>() { + public P2 f(final Integer i) { + return p(a, i); + } + }; + } + }); + } + + /** + * Appends (snoc) the given element to this list to produce a new list. + * + * @param a The element to append to this list. + * @return A new list with the given element appended. + */ + public final List snoc(final A a) { + return fromList(this).snoc(a).toList(); + } + + /** + * Returns true if the predicate holds for all of the elements of this list, + * false otherwise (true for the empty list). + * + * @param f The predicate function to test on each element of this list. + * @return true if the predicate holds for all of the elements of this list, + * false otherwise. + */ + public final boolean forall(final F f) { + return isEmpty() || f.f(head()) && tail().forall(f); + } + + /** + * Returns true if the predicate holds for at least one of the elements of this list, + * false otherwise (false for the empty list). + * + * @param f The predicate function to test on the elements of this list. + * @return true if the predicate holds for at least one of the elements of this + * list. + */ + public final boolean exists(final F f) { + return find(f).isSome(); + } + + /** + * Finds the first occurrence of an element that matches the given predicate or no value if no + * elements match. + * + * @param f The predicate function to test on elements of this list. + * @return The first occurrence of an element that matches the given predicate or no value if no + * elements match. + */ + public final Option find(final F f) { + for (List as = this; as.isNotEmpty(); as = as.tail()) { + if (f.f(as.head())) + return some(as.head()); + } + + return none(); + } + + /** + * Intersperses the given argument between each element of this list. + * + * @param a The separator to intersperse in this list. + * @return A list with the given separator interspersed. + */ + public final List intersperse(final A a) { + return isEmpty() || tail().isEmpty() ? + this : + cons(head(), cons(a, tail().intersperse(a))); + } + + /** + * Intersperses this list through the given list then joins the results. + * + * @param as The list to intersperse through. + * @return This list through the given list then joins the results. + */ + @SuppressWarnings({"unchecked"}) + public final List intercalate(final List> as) { + return join(as.intersperse(this)); + } + + /** + * Removes duplicates according to object equality. + * + * @return A list without duplicates according to object equality. + */ + public final List nub() { + return nub(Equal.anyEqual()); + } + + /** + * Removes duplicates according to the given equality. Warning: O(n^2). + * + * @param eq Equality over the elements. + * @return A list without duplicates. + */ + public final List nub(final Equal eq) { + return isEmpty() ? this : cons(head(), tail().filter(new F() { + public Boolean f(final A a) { + return !eq.eq(a, head()); + } + }).nub(eq)); + } + + /** + * Removes duplicates according to the given ordering. This function is O(n). + * + * @param o An ordering for the elements. + * @return A list without duplicates. + */ + @SuppressWarnings({"unchecked"}) + public final List nub(final Ord o) { + return sort(o).group(o.equal()).map(List.head_()); + } + + /** + * First-class head function. + * + * @return A function that gets the head of a given list. + */ + public static F, A> head_() { + return new F, A>() { + public A f(final List list) { + return list.head(); + } + }; + } + + /** + * First-class tail function. + * + * @return A function that gets the tail of a given list. + */ + public static F, List> tail_() { + return new F, List>() { + public List f(final List list) { + return list.tail(); + } + }; + } + + /** + * Returns a new list of all the items in this list that do not appear in the given list. + * + * @param eq an equality for the items of the lists. + * @param xs a list to subtract from this list. + * @return a list of all the items in this list that do not appear in the given list. + */ + public final List minus(final Equal eq, final List xs) { + return removeAll(compose(Monoid.disjunctionMonoid.sumLeft(), xs.mapM(curry(eq.eq())))); + } + + /** + * Maps the given function of arity-2 across this list and returns a function that applies all the resulting + * functions to a given argument. + * + * @param f A function of arity-2 + * @return A function that, when given an argument, applies the given function to that argument and every element + * in this list. + */ + public final F> mapM(final F> f) { + return sequence_(map(f)); + } + + /** + * Maps the given function across this list by binding through the Option monad. + * + * @param f The function to apply through the this list. + * @return A possible list of values after binding through the Option monad. + */ + public final Option> mapMOption(final F> f) { + return foldRight(new F2>, Option>>() { + public Option> f(final A a, final Option> bs) { + return f.f(a).bind(new F>>() { + public Option> f(final B b) { + return bs.map(new F, List>() { + public List f(final List bbs) { + return bbs.cons(b); + } + }); + } + }); + } + }, Option.>some(List.nil())); + } + + /** + * Maps the given function across this list by binding through the Trampoline monad. + * + * @param f The function to apply through the this list. + * @return A list of values in the Trampoline monad. + */ + public final Trampoline> mapMTrampoline(final F> f) { + return foldRight(new F2>, Trampoline>>() { + public Trampoline> f(final A a, final Trampoline> bs) { + return f.f(a).bind(new F>>() { + public Trampoline> f(final B b) { + return bs.map(new F, List>() { + public List f(final List bbs) { + return bbs.cons(b); + } + }); + } + }); + } + }, Trampoline.>pure(List.nil())); + } + + /** + * Returns the index of the first element in this list which is equal (by the given equality) to the + * query element, or None if there is no such element. + * + * @param e An equality for this list's elements. + * @param a A query element. + * @return The index of the first element in this list which is equal (by the given equality) to the + * query element, or None if there is no such element. + */ + public final Option elementIndex(final Equal e, final A a) { + return lookup(e, zipIndex(), a); + } + + /** + * Returns the last element of this list. Undefined for the empty list. + * + * @return The last element of this list or throws an error if this list is empty. + */ + public final A last() { + A a = head(); + for (List xs = tail(); xs.isNotEmpty(); xs = xs.tail()) + a = xs.head(); + return a; + } + + /** + * Returns all but the last element of this list. Undefiend for the empty list. + * + * @return All but the last element of this list. Undefiend for the empty list. + */ + public final List init() { + List ys = this; + final Buffer a = empty(); + while(ys.isNotEmpty() && ys.tail().isNotEmpty()) { + a.snoc(head()); + ys = ys.tail(); + } + return a.toList(); + } + + /** + * Inserts the given element before the first element that is greater than or equal to it according + * to the given ordering. + * + * @param f An ordering function to compare elements. + * @param x The element to insert. + * @return A new list with the given element inserted before the first element that is greater than or equal to + * it according to the given ordering. + */ + public final List insertBy(final F> f, final A x) { + List ys = this; + Buffer xs = empty(); + while (ys.isNotEmpty() && f.f(x).f(ys.head()) == GT) { + xs = xs.snoc(ys.head()); + ys = ys.tail(); + } + return xs.append(ys.cons(x)).toList(); + } + + /** + * Returns the most common element in this list. + * + * @param o An ordering for the elements of the list. + * @return The most common element in this list. + */ + public final A mode(final Ord o) { + return sort(o).group(o.equal()).maximum(intOrd.comap(List.length_())).head(); + } + + /** + * Groups the elements of this list by a given keyFunction into a {@link TreeMap}. + * The ordering of the keys is determined by {@link fj.Ord#hashOrd()}. + * + * @param keyFunction The function to select the keys for the map. + * @return A TreeMap containing the keys with the accumulated list of matched elements. + */ + public final TreeMap> groupBy(final F keyFunction) { + return groupBy(keyFunction, Ord.hashOrd()); + } + + /** + * Groups the elements of this list by a given keyFunction into a {@link TreeMap}. + * + * @param keyFunction The function to select the keys for the map. + * @param keyOrd An order for the keys of the tree map. + * @return A TreeMap containing the keys with the accumulated list of matched elements. + */ + public final TreeMap> groupBy(final F keyFunction, final Ord keyOrd) { + return groupBy(keyFunction, Function.identity(), keyOrd); + } + + /** + * Groups the elements of this list by a given keyFunction into a {@link TreeMap} and transforms + * the matching elements with the given valueFunction. The ordering of the keys is determined by + * {@link fj.Ord#hashOrd()}. + * + * @param keyFunction The function to select the keys for the map. + * @param valueFunction The function to apply on each matching value. + * @return A TreeMap containing the keys with the accumulated list of matched and mapped elements. + */ + public final TreeMap> groupBy( + final F keyFunction, + final F valueFunction) { + return this.groupBy(keyFunction, valueFunction, Ord.hashOrd()); + } + + /** + * Groups the elements of this list by a given keyFunction into a {@link TreeMap} and transforms + * the matching elements with the given valueFunction. The ordering of the keys is determined by + * the keyOrd parameter. + * + * @param keyFunction The function to select the keys for the map. + * @param valueFunction The function to apply on each matching value. + * @param keyOrd An order for the keys of the tree map. + * @return A TreeMap containing the keys with the accumulated list of matched and mapped elements. + */ + public final TreeMap> groupBy( + final F keyFunction, + final F valueFunction, + final Ord keyOrd) { + return this.groupBy(keyFunction, valueFunction, List.nil(), List::cons, keyOrd); + } + + /** + * Groups the elements of this list by a given keyFunction into a {@link TreeMap} and transforms + * the matching elements with the given valueFunction. The ordering of the keys is determined by + * the keyOrd parameter. + * + * @param keyFunction The function to select the keys for the map. + * @param valueFunction The function to apply on each matching value. + * @param monoid A monoid, which defines the accumulator for the values and the zero value. + * @param keyOrd An order for the keys of the tree map. + * @return A TreeMap containing the keys with the accumulated list of matched and mapped elements. + */ + public final TreeMap groupBy( + final F keyFunction, + final F valueFunction, + final Monoid monoid, + final Ord keyOrd) { + return groupBy(keyFunction, valueFunction, monoid.zero(), + Function.uncurryF2(monoid.sum()), keyOrd); + } + + /** + * Groups the elements of this list by a given keyFunction, applies the valueFunction and + * accumulates the mapped values with the given grouping accumulator function on the grouping + * identity. + * + * @param keyFunction The function to select the keys. + * @param valueFunction The function to apply on each element. + * @param groupingIdentity The identity, or start value, for the grouping. + * @param groupingAcc The accumulator to apply on each matching value. + * @param keyOrd An order for the keys of the tree map. + * @return A TreeMap containing the keys with the accumulated result of matched and mapped + * elements. + */ + public final TreeMap groupBy( + final F keyFunction, + final F valueFunction, + final D groupingIdentity, + final F2 groupingAcc, + final Ord keyOrd) { + return this.foldLeft(map -> element -> { + final B key = keyFunction.f(element); + final C value = valueFunction.f(element); + return map.set(key, map.get(key) + .map(existing -> groupingAcc.f(value, existing)) + .orSome(groupingAcc.f(value, groupingIdentity))); + }, TreeMap.empty(keyOrd) + ); + } + + + + /** + * Returns whether or not all elements in the list are equal according to the given equality test. + * + * @param eq The equality test. + * @return Whether or not all elements in the list are equal according to the given equality test. + */ + public boolean allEqual(final Equal eq) { + return isEmpty() || tail().isEmpty() || eq.eq(head(), tail().head()) && tail().allEqual(eq); + } + + /** + * First-class length. + * + * @return A function that gets the length of a given list. + */ + public static F, Integer> length_() { + return new F, Integer>() { + public Integer f(final List a) { + return a.length(); + } + }; + } + + /** + * Returns the maximum element in this list according to the given ordering. + * + * @param o An ordering for the elements of the list. + * @return The maximum element in this list according to the given ordering. + */ + public final A maximum(final Ord o) { + return foldLeft1(o.max); + } + + /** + * Returns the minimum element in this list according to the given ordering. + * + * @param o An ordering for the elements of the list. + * @return The minimum element in this list according to the given ordering. + */ + public final A minimum(final Ord o) { + return foldLeft1(o.min); + } + + /** + * Projects an immutable collection of this list. + * + * @return An immutable collection of this list. + */ + public final Collection toCollection() { + return new AbstractCollection() { + public Iterator iterator() { + return new Iterator() { + private List xs = List.this; + + public boolean hasNext() { + return xs.isNotEmpty(); + } + + public A next() { + if (xs.isEmpty()) + throw new NoSuchElementException(); + else { + final A a = xs.head(); + xs = xs.tail(); + return a; + } + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + public int size() { + return length(); + } + }; + } + + private static final class Nil extends List { + public static final Nil INSTANCE = new Nil(); + + public A head() { + throw error("head on empty list"); + } + + public List tail() { + throw error("tail on empty list"); + } + } + + private static final class Cons extends List { + private final A head; + private List tail; + + Cons(final A head, final List tail) { + this.head = head; + this.tail = tail; + } + + public A head() { + return head; + } + + public List tail() { + return tail; + } + + private void tail(final List tail) { + this.tail = tail; + } + } + + /** + * Constructs a list from the given elements. + * + * @param as The elements to construct a list with. + * @return A list with the given elements. + */ + public static List list(final A... as) { + return Array.array(as).toList(); + } + + /** + * Returns an empty list. + * + * @return An empty list. + */ + @SuppressWarnings("unchecked") + public static List nil() { + return (Nil) Nil.INSTANCE; + } + + /** + * Returns a function that prepends (cons) an element to a list to produce a new list. + * + * @return A function that prepends (cons) an element to a list to produce a new list. + */ + public static F, List>> cons() { + return new F, List>>() { + public F, List> f(final A a) { + return new F, List>() { + public List f(final List tail) { + return cons(a, tail); + } + }; + } + }; + } + + public static F2, List> cons_() { + return (a, listA) -> cons(a, listA); + } + + /** + * Returns a function that prepends a value to the given list. + * + * @param tail The list to prepend to. + * @return A function that prepends a value to the given list. + */ + public static F> cons(final List tail) { + return new F>() { + public List f(final A a) { + return tail.cons(a); + } + }; + } + + /** + * Returns a function that prepends the given value to a list. + * + * @param a The value to prepend to a list. + * @return A function that prepends the given value to a list. + */ + public static F, List> cons_(final A a) { + return new F, List>() { + public List f(final List as) { + return as.cons(a); + } + }; + } + + /** + * Prepends the given head element to the given tail element to produce a new list. + * + * @param head The element to prepend. + * @param tail The list to prepend to. + * @return The list with the given element prepended. + */ + public static List cons(final A head, final List tail) { + return new Cons(head, tail); + } + + /** + * Returns a function that determines whether a given list is empty. + * + * @return A function that determines whether a given list is empty. + */ + public static F, Boolean> isEmpty_() { + return new F, Boolean>() { + public Boolean f(final List as) { + return as.isEmpty(); + } + }; + } + + /** + * Returns a function that determines whether a given list is not empty. + * + * @return A function that determines whether a given list is not empty. + */ + public static F, Boolean> isNotEmpty_() { + return new F, Boolean>() { + public Boolean f(final List as) { + return as.isNotEmpty(); + } + }; + } + + /** + * Joins the given list of lists using a bind operation. + * + * @param o The list of lists to join. + * @return A new list that is the join of the given lists. + */ + public static List join(final List> o) { + final F, List> id = identity(); + return o.bind(id); + } + + /** + * A first-class version of join + * + * @return A function that joins a list of lists using a bind operation. + */ + public static F>, List> join() { + return new F>, List>() { + public List f(final List> as) { + return join(as); + } + }; + } + + /** + * Unfolds across the given function starting at the given value to produce a list. + * + * @param f The function to unfold across. + * @param b The start value to begin the unfold. + * @return A new list that is a result of unfolding until the function does not produce a value. + */ + public static List unfold(final F>> f, final B b) { + Buffer buf = empty(); + for (Option> o = f.f(b); o.isSome(); o = f.f(o.some()._2())) { + buf = buf.snoc(o.some()._1()); + } + return buf.toList(); + } + + /** + * Transforms a list of pairs into a list of first components and a list of second components. + * + * @param xs The list of pairs to transform.sp + * @return A list of first components and a list of second components. + */ + public static P2, List> unzip(final List> xs) { + Buffer ba = empty(); + Buffer bb = empty(); + for (final P2 p : xs) { + ba = ba.snoc(p._1()); + bb = bb.snoc(p._2()); + } + return P.p(ba.toList(), bb.toList()); + } + + /** + * Returns a list of the given value replicated the given number of times. + * + * @param n The number of times to replicate the given value. + * @param a The value to replicate. + * @return A list of the given value replicated the given number of times. + */ + public static List replicate(final int n, final A a) { + return n <= 0 ? List.nil() : replicate(n - 1, a).cons(a); + } + + /** + * Returns a list of integers from the given from value (inclusive) to the given + * to value (exclusive). + * + * @param from The minimum value for the list (inclusive). + * @param to The maximum value for the list (exclusive). + * @return A list of integers from the given from value (inclusive) to the given + * to value (exclusive). + */ + public static List range(final int from, final int to) { + return from >= to ? List.nil() : cons(from, range(from + 1, to)); + } + + /** + * Returns a list of characters from the given string. The inverse of this function is {@link + * #asString(List)}. + * + * @param s The string to produce the list of characters from. + * @return A list of characters from the given string. + */ + public static List fromString(final String s) { + List cs = nil(); + + for (int i = s.length() - 1; i >= 0; i--) + cs = cons(s.charAt(i), cs); + + return cs; + } + + /** + * A first-class fromString. + * + * @return A first-class fromString. + */ + public static F> fromString() { + return new F>() { + public List f(final String s) { + return fromString(s); + } + }; + } + + /** + * Returns a string from the given list of characters. The invers of this function is {@link + * #fromString(String)}. + * + * @param cs The list of characters to produce the string from. + * @return A string from the given list of characters. + */ + public static String asString(final List cs) { + final StringBuilder sb = new StringBuilder(); + + cs.foreach(new F() { + public Unit f(final Character c) { + sb.append(c); + return unit(); + } + }); + return sb.toString(); + } + + /** + * A first-class asString. + * + * @return A first-class asString. + */ + public static F, String> asString() { + return new F, String>() { + public String f(final List cs) { + return asString(cs); + } + }; + } + + /** + * Returns a list of one element containing the given value. + * + * @param a The value for the head of the returned list. + * @return A list of one element containing the given value. + */ + public static List single(final A a) { + return cons(a, List.nil()); + } + + /** + * Creates a list where the first item is calculated by applying the function on the third argument, + * the second item by applying the function on the previous result and so on. + * + * @param f The function to iterate with. + * @param p The predicate which must be true for the next item in order to continue the iteration. + * @param a The input to the first iteration. + * @return A list where the first item is calculated by applying the function on the third argument, + * the second item by applying the function on the previous result and so on. + */ + public static List iterateWhile(final F f, final F p, final A a) { + return unfold( + new F>>() { + public Option> f(final A o) { + return Option.iif(new F, Boolean>() { + public Boolean f(final P2 p2) { + return p.f(o); + } + }, P.p(o, f.f(o))); + } + } + , a); + } + + /** + * Returns an associated value with the given key in the list of pairs. + * + * @param e The test for equality on keys. + * @param x The list of pairs to search. + * @param a The key value to find the associated value of. + * @return An associated value with the given key in the list of pairs. + */ + public static Option lookup(final Equal e, final List> x, final A a) { + return x.find(new F, Boolean>() { + public Boolean f(final P2 p) { + return e.eq(p._1(), a); + } + }).map(P2.__2()); + } + + /** + * Returns a partially applied version of {@link #lookup(Equal, List, Object)}. + * + * @param e The test for equality on keys. + * @return A partially applied version of {@link #lookup(Equal , List, Object)}. + */ + public static F2>, A, Option> lookup(final Equal e) { + return new F2>, A, Option>() { + public Option f(final List> x, final A a) { + return lookup(e, x, a); + } + }; + } + + /** + * Provides a first-class version of bind() + * + * @return The bind function for lists. + */ + public static F>, F, List>> bind_() { + return curry(new F2>, List, List>() { + public List f(final F> f, final List as) { + return as.bind(f); + } + }); + } + + /** + * Provides a first-class version of map() + * + * @return The map function for lists. + */ + public static F, F, List>> map_() { + return curry(new F2, List, List>() { + public List f(final F f, final List as) { + return as.map(f); + } + }); + } + + /** + * Turn a list of functions into a function returning a list. + * + * @param fs The list of functions to sequence into a single function that returns a list. + * @return A function that, when given an argument, applies all the functions in the given list to it + * and returns a list of the results. + */ + public static F> sequence_(final List> fs) { + return fs.foldRight(Function., List, B>lift(List.cons()), Function + .>constant(List.nil())); + } + + /** + * Provides a first-class version of foldLeft. + * + * @return The left fold function for lists. + */ + public static F>, F, B>>> foldLeft() { + return curry(new F3>, B, List, B>() { + public B f(final F> f, final B b, final List as) { + return as.foldLeft(f, b); + } + }); + } + + /** + * Provides a first-class version of take. + * + * @return First-class version of take. + */ + public static F, List>> take() { + return curry(new F2, List>() { + public List f(final Integer n, final List as) { + return as.take(n); + } + }); + } + + /** + * Takes the given iterable to a list. + * + * @param i The iterable to take to a list. + * @return A list from the given iterable. + */ + public static List iterableList(final Iterable i) { + final Buffer bs = empty(); + + for (final A a : i) + bs.snoc(a); + + return bs.toList(); + } + + + /** + * A mutable, singly linked list. This structure should be used very sparingly, in favour + * of the {@link List immutable singly linked list structure}. + */ + public static final class Buffer implements Iterable { + private List start = nil(); + private Cons tail; + private boolean exported; + + /** + * Returns an iterator for this buffer. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this buffer. + */ + public Iterator iterator() { + return start.iterator(); + } + + /** + * Appends (snoc) the given element to this buffer to produce a new buffer. + * + * @param a The element to append to this buffer. + * @return A new buffer with the given element appended. + */ + public Buffer snoc(final A a) { + if (exported) + copy(); + + final Cons t = new Cons(a, List.nil()); + + if (tail == null) + start = t; + else + tail.tail(t); + + tail = t; + + return this; + } + + /** + * Appends the given buffer to this buffer. + * + * @param as The buffer to append to this one. + * @return A new buffer that has appended the given buffer. + */ + public Buffer append(final List as) { + for (List xs = as; xs.isNotEmpty(); xs = xs.tail()) + snoc(xs.head()); + + return this; + } + + /** + * Returns an immutable list projection of this buffer. Modifications to the underlying buffer + * will not be reflected in returned lists. + * + * @return An immutable list projection of this buffer. + */ + public List toList() { + exported = !start.isEmpty(); + return start; + } + + /** + * Projects an immutable collection of this buffer. + * + * @return An immutable collection of this buffer. + */ + public Collection toCollection() { + return start.toCollection(); + } + + /** + * An empty buffer. + * + * @return An empty buffer. + */ + public static Buffer empty() { + return new Buffer(); + } + + /** + * Constructs a buffer from the given list. + * + * @param as The list to construct a buffer with. + * @return A buffer from the given list. + */ + public static Buffer fromList(final List as) { + final Buffer b = new Buffer(); + + for (List xs = as; xs.isNotEmpty(); xs = xs.tail()) + b.snoc(xs.head()); + + return b; + } + + /** + * Takes the given iterable to a buffer. + * + * @param i The iterable to take to a buffer. + * @return A buffer from the given iterable. + */ + public static Buffer iterableBuffer(final Iterable i) { + final Buffer b = empty(); + + for (final A a : i) + b.snoc(a); + + return b; + } + + @SuppressWarnings({"ObjectEquality"}) + private void copy() { + List s = start; + final Cons t = tail; + start = nil(); + exported = false; + while (s != t) { + snoc(s.head()); + s = s.tail(); + } + + if (t != null) + snoc(t.head()); + } + } + + /** + * Perform an equality test on this list which delegates to the .equals() method of the member instances. + * This is implemented with Equal.listEqual using the anyEqual rule. + * + * @param obj the other object to check for equality against. + * @return true if this list is equal to the provided argument + */ + //Suppress the warning for cast to List because the type is checked in the previous line. + @SuppressWarnings({ "unchecked" }) + @Override public boolean equals( final Object obj ) { + if ( obj == null || !( obj instanceof List ) ) { return false; } + + //Casting to List here does not cause a runtime exception even if the type arguments don't match. + //The cast is done to avoid the compiler warning "raw use of parameterized class 'List'" + return Equal.listEqual( Equal.anyEqual() ).eq( this, (List) obj ); + } + + /** + * Compute the hash code from this list as a function of the hash codes of its members. + * Delegates to Hash.listHash, using the anyHash() rule, which uses the hash codes of the contents. + * + * @return the hash code for this list. + */ + @Override public int hashCode() { + return Hash.listHash( Hash.anyHash() ).hash( this ); + } + + /** + * Obtain a string representation of this list using the toString implementations of the members. Uses Show.listShow with F2 argument and may + * not be very performant. + * + * @return a String representation of the list + */ + @Override public String toString() { + return Show.listShow( Show.anyShow() ).show( this ).foldLeft( new F2() { + @Override public String f( final String s, final Character c ) { + return s + c; + } + }, "" ); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Natural.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Natural.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,329 @@ +package fj.data; + +import static fj.Bottom.error; +import fj.F; +import fj.F2; +import static fj.Monoid.naturalAdditionMonoid; +import static fj.Monoid.naturalMultiplicationMonoid; +import static fj.Function.curry; +import fj.data.vector.V2; +import fj.data.vector.V; + +import java.math.BigInteger; + +/** + * Represents a natural number (zero, one, two, etc.) + */ +public final class Natural extends Number { + private final BigInteger value; + private static final long serialVersionUID = -588673650944359682L; + + private Natural(final BigInteger i) { + if (i.compareTo(BigInteger.ZERO) < 0) + throw error("Natural less than zero"); + value = i; + } + + /** + * Returns the natural number equal to the given BigInteger + * + * @param i A given BigInteger + * @return An optional natural number, or none if the given BigInteger is less than zero. + */ + public static Option natural(final BigInteger i) { + return i.compareTo(BigInteger.ZERO) < 0 + ? Option.none() + : Option.some(new Natural(i)); + } + + /** + * A function that returns the natural number equal to a given BigInteger + */ + public static final F> fromBigInt = + new F>() { + public Option f(final BigInteger i) { + return natural(i); + } + }; + + /** + * Returns the natural number equal to the given long + * + * @param i A given long + * @return An optional natural number, or none if the given long is less than zero. + */ + public static Option natural(final long i) { + return natural(BigInteger.valueOf(i)); + } + + /** + * The natural number zero + */ + public static final Natural ZERO = natural(0).some(); + + /** + * The natural number one + */ + public static final Natural ONE = natural(1).some(); + + /** + * Return the successor of this natural number + * + * @return the successor of this natural number + */ + public Natural succ() { + return add(ONE); + } + + /** + * First-class successor function. + * + * @return A function that returns the successor of a given natural number. + */ + public static F succ_() { + return new F() { + public Natural f(final Natural natural) { + return natural.succ(); + } + }; + } + + /** + * Return the predecessor of this natural number + * + * @return the predecessor of this natural number + */ + public Option pred() { + return subtract(ONE); + } + + /** + * First-class predecessor function. + * + * @return A function that returns the predecessor of a given natural number, or None if it's zero. + */ + public static F> pred_() { + return new F>() { + public Option f(final Natural natural) { + return natural.pred(); + } + }; + } + + /** + * Add two natural numbers together. + * + * @param n A natural number to add to this one. + * @return the sum of the two natural numbers. + */ + public Natural add(final Natural n) { + return natural(n.value.add(value)).some(); + } + + /** + * A function that adds two natural numbers. + */ + public static final F> add = curry(new F2() { + public Natural f(final Natural n1, final Natural n2) { + return n1.add(n2); + } + }); + + + /** + * Subtract a natural number from another. + * + * @param n A natural number to subtract from this one. + * @return The difference between the two numbers, if this number is larger than the given one. Otherwise none. + */ + public Option subtract(final Natural n) { + return natural(n.value.subtract(value)); + } + + /** + * A function that subtracts its first argument from its second. + */ + public static final F>> subtract = + curry(new F2>() { + public Option f(final Natural o, final Natural o1) { + return o1.subtract(o); + } + }); + + /** + * Multiply a natural number by another. + * + * @param n A natural number to multiply by this one. + * @return The product of the two numbers. + */ + public Natural multiply(final Natural n) { + return natural(n.value.multiply(value)).some(); + } + + /** + * A function that multiplies a natural number by another. + */ + public static final F> multiply = curry(new F2() { + public Natural f(final Natural n1, final Natural n2) { + return n1.multiply(n2); + } + }); + + + /** + * A function that divides its second argument by its first. + */ + public static final F> divide = + curry(new F2() { + public Natural f(final Natural n1, final Natural n2) { + return n2.divide(n1); + } + }); + + /** + * Divide a natural number by another. + * + * @param n A natural number to divide this one by. + * @return The quotient of this number and the highest number, less than or equal to the given number, + * that divides this number. + */ + public Natural divide(final Natural n) { + return natural(value.divide(n.value)).some(); + } + + /** + * Take the remainder of a natural number division. + * + * @param n A natural number to divide this one by. + * @return The remainder of division of this number by the given number. + */ + public Natural mod(final Natural n) { + return natural(value.mod(n.value)).some(); + } + + /** + * A function that yields the remainder of division of its second argument by its first. + */ + public static final F> mod = + curry(new F2() { + public Natural f(final Natural n1, final Natural n2) { + return n2.mod(n1); + } + }); + + /** + * Divide a natural number by another yielding both the quotient and the remainder. + * + * @param n A natural number to divide this one by. + * @return The quotient and the remainder, in that order. + */ + public V2 divmod(final Natural n) { + final BigInteger[] x = value.divideAndRemainder(n.value); + return V.v(natural(x[0]).some(), natural(x[1]).some()); + } + + /** + * A function that divides its second argument by its first, yielding both the quotient and the remainder. + */ + public static final F>> divmod = + curry(new F2>() { + public V2 f(final Natural n1, final Natural n2) { + return n2.divmod(n1); + } + }); + + + /** + * Return the BigInteger value of this natural number. + * + * @return the BigInteger value of this natural number. + */ + public BigInteger bigIntegerValue() { + return value; + } + + /** + * Return the long value of this natural number. + * + * @return the long value of this natural number. + */ + public long longValue() { + return value.longValue(); + } + + /** + * Return the float value of this natural number. + * + * @return the float value of this natural number. + */ + public float floatValue() { + return value.floatValue(); + } + + /** + * Return the double value of this natural number. + * + * @return the double value of this natural number. + */ + public double doubleValue() { + return value.doubleValue(); + } + + /** + * Return the int value of this natural number. + * + * @return the int value of this natural number. + */ + public int intValue() { + return value.intValue(); + } + + /** + * A function that returns the BigInteger value of a given Natural. + */ + public static final F bigIntegerValue = new F() { + public BigInteger f(final Natural n) { + return n.bigIntegerValue(); + } + }; + + /** + * Sums a stream of natural numbers. + * + * @param ns A stream of natural numbers. + * @return The sum of all the natural numbers in the stream. + */ + public static Natural sum(final Stream ns) { + return naturalAdditionMonoid.sumLeft(ns); + } + + /** + * Takes the product of a stream of natural numbers. + * + * @param ns A stream of natural numbers. + * @return The product of all the natural numbers in the stream. + */ + public static Natural product(final Stream ns) { + return naturalMultiplicationMonoid.sumLeft(ns); + } + + /** + * Sums a list of natural numbers. + * + * @param ns A list of natural numbers. + * @return The sum of all the natural numbers in the list. + */ + public static Natural sum(final List ns) { + return naturalAdditionMonoid.sumLeft(ns); + } + + /** + * Takes the product of a list of natural numbers. + * + * @param ns A list of natural numbers. + * @return The product of all the natural numbers in the list. + */ + public static Natural product(final List ns) { + return naturalMultiplicationMonoid.sumLeft(ns); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/NonEmptyList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/NonEmptyList.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,218 @@ +package fj.data; + +import fj.F; +import fj.F1Functions; +import fj.function.Effect1; + +import static fj.data.Option.some; +import static fj.data.Option.somes; + +import java.util.Collection; +import java.util.Iterator; + +/** + * Provides an in-memory, immutable, singly linked list with total head and tail. + * + * @version %build.number% + */ +public final class NonEmptyList implements Iterable { + /** + * Returns an iterator for this non-empty list. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this non-empty list. + */ + + public Iterator iterator() { + return toCollection().iterator(); + } + + /** + * The first element of this linked list. + */ + @SuppressWarnings({"PublicField", "ClassEscapesDefinedScope"}) + public final A head; + + /** + * This list without the first element. + */ + @SuppressWarnings({"PublicField"}) + public final List tail; + + private NonEmptyList(final A head, final List tail) { + this.head = head; + this.tail = tail; + } + + /** + * Prepend the given value to this list. + * + * @param a The value to prepend. + * @return A non-empty list with an extra element. + */ + public NonEmptyList cons(final A a) { + return nel(a, tail.cons(head)); + } + + /** + * Appends the given list to this list. + * + * @param as The list to append. + * @return A new list with the given list appended. + */ + public NonEmptyList append(final NonEmptyList as) { + final List.Buffer b = new List.Buffer(); + b.append(tail); + b.snoc(as.head); + b.append(as.tail); + final List bb = b.toList(); + return nel(head, bb); + } + + /** + * Maps the given function across this list. + * + * @param f The function to map across this list. + * @return A new list after the given function has been applied to each element. + */ + public NonEmptyList map(final F f) { + return nel(f.f(head), tail.map(f)); + } + + /** + * Binds the given function across each element of this list with a final join. + * + * @param f The function to apply to each element of this list. + * @return A new list after performing the map, then final join. + */ + public NonEmptyList bind(final F> f) { + final List.Buffer b = new List.Buffer(); + final NonEmptyList p = f.f(head); + b.snoc(p.head); + b.append(p.tail); + tail.foreachDoEffect(new Effect1() { + public void f(final A a) { + final NonEmptyList p = f.f(a); + b.snoc(p.head); + b.append(p.tail); + } + }); + final List bb = b.toList(); + return nel(bb.head(), bb.tail()); + } + + /** + * Returns a NonEmptyList of the sublists of this list. + * + * @return a NonEmptyList of the sublists of this list. + */ + public NonEmptyList> sublists() { + return fromList( + somes(toList().toStream().substreams() + .map(F1Functions.o(new F, Option>>() { + public Option> f(final List list) { + return fromList(list); + } + }, Conversions.Stream_List())).toList())).some(); + } + + /** + * Returns a NonEmptyList of the tails of this list. A list is considered a tail of itself for the purpose of this + * function (Comonad pattern). + * + * @return A NonEmptyList of the tails of this list. + */ + public NonEmptyList> tails() { + return fromList(somes(toList().tails().map(new F, Option>>() { + public Option> f(final List list) { + return fromList(list); + } + }))).some(); + } + + /** + * Maps the given function across the tails of this list (comonad pattern). + * + * @param f The function to map across the tails of this list. + * @return The results of applying the given function to the tails of this list, as a NonEmptyList. + */ + public NonEmptyList mapTails(final F, B> f) { + return tails().map(f); + } + + /** + * Returns a List projection of this list. + * + * @return A List projection of this list. + */ + public List toList() { + return tail.cons(head); + } + + /** + * Projects an immutable collection of this non-empty list. + * + * @return An immutable collection of this non-empty list. + */ + public Collection toCollection() { + return toList().toCollection(); + } + + /** + * Returns a function that takes a non-empty list to a list. + * + * @return A function that takes a non-empty list to a list. + */ + public static F, List> toList_() { + return new F, List>() { + public List f(final NonEmptyList as) { + return as.toList(); + } + }; + } + + /** + * Return a non-empty list with the given head and tail. + * + * @param head The first element of the new list. + * @param tail The remaining elements of the new list. + * @return A non-empty list with the given head and tail. + */ + public static NonEmptyList nel(final A head, final List tail) { + return new NonEmptyList(head, tail); + } + + /** + * Return a non-empty list with the given value. + * + * @param head The value in the non-empty list. + * @return A non-empty list with the given value. + */ + public static NonEmptyList nel(final A head) { + return nel(head, List.nil()); + } + + /** + * Returns a function that puts an element into a non-empty list. + * + * @return A function that puts an element into a non-empty list. + */ + public static F> nel() { + return new F>() { + public NonEmptyList f(final A a) { + return nel(a); + } + }; + } + + /** + * Returns a potential non-empty list from the given list. A non-value is returned if the given list is empty. + * + * @param as The list to construct a potential non-empty list with. + * @return A potential non-empty list from the given list. + */ + public static Option> fromList(final List as) { + return as.isEmpty() ? + Option.>none() : + some(nel(as.head(), as.tail())); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Option.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Option.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,964 @@ +package fj.data; + +import static fj.Bottom.error; + +import fj.Effect; +import fj.F; +import fj.F2; +import fj.P; +import fj.P1; +import fj.P2; +import fj.P3; +import fj.P4; +import fj.P5; +import fj.P6; +import fj.P7; +import fj.P8; +import fj.Unit; +import fj.Show; +import fj.function.Effect1; + +import static fj.Function.*; +import static fj.P.p; +import static fj.Unit.unit; +import static fj.data.List.cons; +import static fj.data.List.cons_; +import static fj.data.Validation.parseByte; +import static fj.data.Validation.parseDouble; +import static fj.data.Validation.parseFloat; +import static fj.data.Validation.parseInt; +import static fj.data.Validation.parseLong; +import static fj.data.Validation.parseShort; +import static fj.Show.optionShow; +import static fj.Show.anyShow; + +import java.util.Collection; +import java.util.Iterator; + +/** + * An optional value that may be none (no value) or some (a value). This type is a replacement for + * the use of null with better type checks. + * + * @version %build.number% + */ +public abstract class Option implements Iterable { + private Option() { + + } + + public String toString() { + final Show s = anyShow(); + return optionShow(s).showS(this); + } + + /** + * Returns an iterator for this optional value. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this optional value. + */ + public final Iterator iterator() { + return toCollection().iterator(); + } + + /** + * Returns the value from this optional value, or fails if there is no value. + * + * @return The value from this optional value, or fails if there is no value. + */ + public abstract A some(); + + /** + * Returns true if this optional value has a value, false otherwise. + * + * @return true if this optional value has a value, false otherwise. + */ + public final boolean isSome() { + return this instanceof Some; + } + + /** + * Returns false if this optional value has a value, true otherwise. + * + * @return false if this optional value has a value, true otherwise. + */ + public final boolean isNone() { + return this instanceof None; + } + + /** + * A first-class version of the isSome method. + * + * @return A function that returns true if a given optional value has a value, otherwise false. + */ + public static F, Boolean> isSome_() { + return new F, Boolean>() { + public Boolean f(final Option a) { + return a.isSome(); + } + }; + } + + /** + * A first-class version of the isNone method. + * + * @return A function that returns false if a given optional value has a value, otherwise true. + */ + public static F, Boolean> isNone_() { + return new F, Boolean>() { + public Boolean f(final Option a) { + return a.isNone(); + } + }; + } + + /** + * Performs a reduction on this optional value using the given arguments. + * + * @param b The value to return if this optional value has no value. + * @param f The function to apply to the value of this optional value. + * @return A reduction on this optional value. + */ + public final B option(final B b, final F f) { + return isSome() ? f.f(some()) : b; + } + + /** + * Performs a reduction on this optional value using the given arguments. + * + * @param b The value to return if this optional value has no value. + * @param f The function to apply to the value of this optional value. + * @return A reduction on this optional value. + */ + public final B option(final P1 b, final F f) { + return isSome() ? f.f(some()) : b._1(); + } + + /** + * Returns the length of this optional value; 1 if there is a value, 0 otherwise. + * + * @return The length of this optional value; 1 if there is a value, 0 otherwise. + */ + public final int length() { + return isSome() ? 1 : 0; + } + + /** + * Returns the value of this optional value or the given argument. + * + * @param a The argument to return if this optiona value has no value. + * @return The value of this optional value or the given argument. + */ + public final A orSome(final P1 a) { + return isSome() ? some() : a._1(); + } + + /** + * Returns the value of this optional value or the given argument. + * + * @param a The argument to return if this optiona value has no value. + * @return The value of this optional value or the given argument. + */ + public final A orSome(final A a) { + return isSome() ? some() : a; + } + + /** + * Returns the value of this optional value or fails with the given message. + * + * @param message The message to fail with if this optional value has no value. + * @return The value of this optional value if there there is one. + */ + public final A valueE(final P1 message) { + if(isSome()) + return some(); + else + throw error(message._1()); + } + + /** + * Returns the value of this optional value or fails with the given message. + * + * @param message The message to fail with if this optional value has no value. + * @return The value of this optional value if there there is one. + */ + public final A valueE(final String message) { + if(isSome()) + return some(); + else + throw error(message); + } + + /** + * Maps the given function across this optional value. + * + * @param f The function to map across this optional value. + * @return A new optional value after the given function has been applied to its element. + */ + public final Option map(final F f) { + return isSome() ? some(f.f(some())) : Option.none(); + } + + /** + * A first-class map function. + * + * @return A function that maps a given function across a given optional value. + */ + public static F, F, Option>> map() { + return curry(new F2, Option, Option>() { + public Option f(final F abf, final Option option) { + return option.map(abf); + } + }); + } + + /** + * Performs a side-effect for the value of this optional value. + * + * @param f The side-effect to perform for the given element. + * @return The unit value. + */ + public final Unit foreach(final F f) { + return isSome() ? f.f(some()) : unit(); + } + + /** + * Performs a side-effect for the value of this optional value. + * + * @param f The side-effect to perform for the given element. + */ + public final void foreachDoEffect(final Effect1 f) { + if (isSome()) + f.f(some()); + } + + /** + * Filters elements from this optional value by returning only elements which produce + * true when the given function is applied to them. + * + * @param f The predicate function to filter on. + * @return A new optional value whose value matches the given predicate if it has one. + */ + public final Option filter(final F f) { + return isSome() ? f.f(some()) ? this : Option.none() : Option.none(); + } + + /** + * Binds the given function across the element of this optional value with a final join. + * + * @param f The function to apply to the element of this optional value. + * @return A new optional value after performing the map, then final join. + */ + public final Option bind(final F> f) { + return isSome() ? f.f(some()) : Option.none(); + } + + /** + * Binds the given function across the element of this optional value and the given optional value + * with a final join. + * + * @param ob A given optional value to bind the given function with. + * @param f The function to apply to the element of this optional value and the given optional + * value. + * @return A new optional value after performing the map, then final join. + */ + public final Option bind(final Option ob, final F> f) { + return ob.apply(map(f)); + } + + /** + * Binds the given function across the element of this optional value and the given optional value + * with a final join. + * + * @param ob A given optional value to bind the given function with. + * @param oc A given optional value to bind the given function with. + * @param f The function to apply to the element of this optional value and the given optional + * value. + * @return A new optional value after performing the map, then final join. + */ + public final Option bind(final Option ob, final Option oc, final F>> f) { + return oc.apply(bind(ob, f)); + } + + /** + * Binds the given function across the element of this optional value and the given optional value + * with a final join. + * + * @param ob A given optional value to bind the given function with. + * @param oc A given optional value to bind the given function with. + * @param od A given optional value to bind the given function with. + * @param f The function to apply to the element of this optional value and the given optional + * value. + * @return A new optional value after performing the map, then final join. + */ + public final Option bind(final Option ob, final Option oc, final Option od, + final F>>> f) { + return od.apply(bind(ob, oc, f)); + } + + /** + * Binds the given function across the element of this optional value and the given optional value + * with a final join. + * + * @param ob A given optional value to bind the given function with. + * @param oc A given optional value to bind the given function with. + * @param od A given optional value to bind the given function with. + * @param oe A given optional value to bind the given function with. + * @param f The function to apply to the element of this optional value and the given optional + * value. + * @return A new optional value after performing the map, then final join. + */ + public final Option bind(final Option ob, final Option oc, final Option od, + final Option oe, final F>>>> f) { + return oe.apply(bind(ob, oc, od, f)); + } + + /** + * Binds the given function across the element of this optional value and the given optional value + * with a final join. + * + * @param ob A given optional value to bind the given function with. + * @param oc A given optional value to bind the given function with. + * @param od A given optional value to bind the given function with. + * @param oe A given optional value to bind the given function with. + * @param of A given optional value to bind the given function with. + * @param f The function to apply to the element of this optional value and the given optional + * value. + * @return A new optional value after performing the map, then final join. + */ + public final Option bind(final Option ob, final Option oc, final Option od, + final Option oe, final Option of, + final F>>>>> f) { + return of.apply(bind(ob, oc, od, oe, f)); + } + + /** + * Binds the given function across the element of this optional value and the given optional value + * with a final join. + * + * @param ob A given optional value to bind the given function with. + * @param oc A given optional value to bind the given function with. + * @param od A given optional value to bind the given function with. + * @param oe A given optional value to bind the given function with. + * @param of A given optional value to bind the given function with. + * @param og A given optional value to bind the given function with. + * @param f The function to apply to the element of this optional value and the given optional + * value. + * @return A new optional value after performing the map, then final join. + */ + public final Option bind(final Option ob, final Option oc, final Option od, + final Option oe, final Option of, final Option og, + final F>>>>>> f) { + return og.apply(bind(ob, oc, od, oe, of, f)); + } + + /** + * Binds the given function across the element of this optional value and the given optional value + * with a final join. + * + * @param ob A given optional value to bind the given function with. + * @param oc A given optional value to bind the given function with. + * @param od A given optional value to bind the given function with. + * @param oe A given optional value to bind the given function with. + * @param of A given optional value to bind the given function with. + * @param og A given optional value to bind the given function with. + * @param oh A given optional value to bind the given function with. + * @param f The function to apply to the element of this optional value and the given optional + * value. + * @return A new optional value after performing the map, then final join. + */ + public final Option bind(final Option ob, final Option oc, final Option od, + final Option oe, final Option of, final Option og, + final Option oh, + final F>>>>>>> f) { + return oh.apply(bind(ob, oc, od, oe, of, og, f)); + } + + public final Option> bindProduct(final Option ob) { + return bind(ob, P.p2()); + } + + public final Option> bindProduct(final Option ob, final Option oc) { + return bind(ob, oc, P.p3()); + } + + public final Option> bindProduct(final Option ob, final Option oc, final Option od) { + return bind(ob, oc, od, P.p4()); + } + + public final Option> bindProduct(final Option ob, final Option oc, final Option od, + final Option oe) { + return bind(ob, oc, od, oe, P.p5()); + } + + public final Option> bindProduct(final Option ob, final Option oc, final Option od, + final Option oe, final Option of) { + return bind(ob, oc, od, oe, of, P.p6()); + } + + public final Option> bindProduct(final Option ob, final Option oc, + final Option od, final Option oe, + final Option of, final Option og) { + return bind(ob, oc, od, oe, of, og, P.p7()); + } + + public final Option> bindProduct(final Option ob, final Option oc, + final Option od, final Option oe, + final Option of, final Option og, + final Option oh) { + return bind(ob, oc, od, oe, of, og, oh, P.p8()); + } + + /** + * Performs a bind across the optional value, but ignores the element value in the function. + * + * @param o The optional value to apply in the final join. + * @return A new optional value after the final join. + */ + public final Option sequence(final Option o) { + final F> c = constant(o); + return bind(c); + } + + /** + * Performs function application within an optional value (applicative functor pattern). + * + * @param of The optional value of functions to apply. + * @return A new optional value after applying the given optional value of functions through this + * optional value. + */ + public final Option apply(final Option> of) { + return of.bind(new F, Option>() { + public Option f(final F f) { + return map(new F() { + public B f(final A a) { + return f.f(a); + } + }); + } + }); + } + + /** + * Returns this optional value if there is one, otherwise, returns the argument optional value. + * + * @param o The optional value to return if this optional value has no value. + * @return This optional value if there is one, otherwise, returns the argument optional value. + */ + public final Option orElse(final P1> o) { + return isSome() ? this : o._1(); + } + + /** + * Returns this optional value if there is one, otherwise, returns the argument optional value. + * + * @param o The optional value to return if this optional value has no value. + * @return This optional value if there is one, otherwise, returns the argument optional value. + */ + public final Option orElse(final Option o) { + return isSome() ? this : o; + } + + /** + * Returns an either projection of this optional value; the given argument in Left if + * no value, or the value in Right. + * + * @param x The value to return in left if this optional value has no value. + * @return An either projection of this optional value. + */ + public final Either toEither(final P1 x) { + return isSome() ? Either.right(some()) : Either.left(x._1()); + } + + /** + * Returns an either projection of this optional value; the given argument in Left if + * no value, or the value in Right. + * + * @param x The value to return in left if this optional value has no value. + * @return An either projection of this optional value. + */ + public final Either toEither(final X x) { + return isSome() ? Either.right(some()) : Either.left(x); + } + + public final Validation toValidation(final X x) { + return Validation.validation(toEither(x)); + } + + /** + * A first-class version of the toEither method. + * + * @return A function that returns an either projection of a given optional value, given a value to + * return in left. + */ + public static F, F>> toEither() { + return curry(new F2, X, Either>() { + public Either f(final Option a, final X x) { + return a.toEither(x); + } + }); + } + + /** + * Returns a list projection of this optional value. + * + * @return A list projection of this optional value. + */ + public final List toList() { + return isSome() ? cons(some(), List.nil()) : List.nil(); + } + + /** + * Returns a stream projection of this optional value. + * + * @return A stream projection of this optional value. + */ + public final Stream toStream() { + return isSome() ? Stream.nil().cons(some()) : Stream.nil(); + } + + /** + * Returns an array projection of this optional value. + * + * @return An array projection of this optional value. + */ + @SuppressWarnings({"unchecked"}) + public final Array toArray() { + return isSome() ? Array.array(some()) : Array.empty(); + } + + /** + * Returns an array projection of this optional value. + * + * @param c The class type of the array to return. + * @return An array projection of this optional value. + */ + @SuppressWarnings({"unchecked"}) + public final Array toArray(final Class c) { + if (isSome()) { + final A[] a = (A[]) java.lang.reflect.Array.newInstance(c.getComponentType(), 1); + a[0] = some(); + return Array.array(a); + } else + return Array.array((A[]) java.lang.reflect.Array.newInstance(c.getComponentType(), 0)); + } + + /** + * Returns an array from this optional value. + * + * @param c The class type of the array to return. + * @return An array from this optional value. + */ + public final A[] array(final Class c) { + return toArray(c).array(c); + } + + /** + * Returns the value from this optional value, or if there is no value, returns null. + * This is intended for interfacing with APIs that expect a null for non-existence. + * + * @return This optional value or null if there is no value. + */ + public final A toNull() { + return orSome((A) null); + } + + /** + * Returns true if this optional value has no value, or the predicate holds for the + * given predicate function, false otherwise. + * + * @param f the predicate function to test on the value of this optional value. + * @return true if this optional value has no value, or the predicate holds for the + * given predicate function, false otherwise. + */ + public final boolean forall(final F f) { + return isNone() || f.f(some()); + } + + /** + * Returns true is this optional value has a value and the given predicate function + * holds on that value, false otherwise. + * + * @param f the predicate function to test on the value of this optional value. + * @return true is this optional value has a value and the given predicate function + * holds on that value, false otherwise. + */ + public final boolean exists(final F f) { + return isSome() && f.f(some()); + } + + /** + * Projects an immutable collection of this optional value. + * + * @return An immutable collection of this optional value. + */ + public final Collection toCollection() { + return toList().toCollection(); + } + + private static final class None extends Option { + public A some() { + throw error("some on None"); + } + + @Override + public int hashCode() { + return 31; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + return true; + } + } + + private static final class Some extends Option { + private final A a; + + Some(final A a) { + this.a = a; + } + + public A some() { + return a; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((a == null) ? 0 : a.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Some other = (Some) obj; + if (a == null) { + if (other.a != null) + return false; + } else if (!a.equals(other.a)) + return false; + return true; + } + + } + + public static F> some_() { + return new F>() { + public Option f(final T t) { + return some(t); + } + }; + } + + /** + * Constructs an optional value that has a value of the given argument. + * + * @param t The value for the returned optional value. + * @return An optional value that has a value of the given argument. + */ + public static Option some(final T t) { + return new Some(t); + } + + public static F> none_() { + return new F>() { + public Option f(final T t) { + return none(); + } + }; + } + + /** + * Constructs an optional value that has no value. + * + * @return An optional value that has no value. + */ + public static Option none() { + return new None(); + } + + /** + * Turns an unsafe nullable value into a safe optional value. If t == null then + * return none, otherwise, return the given value in some. + * + * @param t The unsafe nullable value. + * @return If t == null then return it in some, otherwise, return none. + */ + public static Option fromNull(final T t) { + return t == null ? Option.none() : some(t); + } + + /** + * Turns an unsafe nullable value into a safe optional value. If t == null then + * return none, otherwise, return the given value in some. + * + * @return If t == null then return it in some, otherwise, return none. + */ + public static F> fromNull() { + return new F>() { + public Option f(final T t) { + return fromNull(t); + } + }; + } + + /** + * Joins the given optional value of optional value using a bind operation. + * + * @param o The optional value of optional value to join. + * @return A new optional value that is the join of the given optional value. + */ + public static Option join(final Option> o) { + final F, Option> id = identity(); + return o.bind(id); + } + + /** + * Sequence through the option monad. + * + * @param a The list of option to sequence. + * @return The option of list after sequencing. + */ + public static Option> sequence(final List> a) { + return a.isEmpty() ? + some(List.nil()) : + a.head().bind(new F>>() { + public Option> f(final A aa) { + return sequence(a.tail()).map(cons_(aa)); + } + }); + } + + /** + * Returns an optional value that has a value of the given argument, if the given predicate holds + * on that argument, otherwise, returns no value. + * + * @param f The predicate to test on the given argument. + * @param a The argument to test the predicate on and potentially use as the value of the returned + * optional value. + * @return an optional value that has a value of the given argument, if the given predicate holds + * on that argument, otherwise, returns no value. + */ + public static Option iif(final F f, final A a) { + return f.f(a) ? some(a) : Option.none(); + } + + /** + * Returns an optional value that has a value of the given argument if the given boolean is true, otherwise, returns + * no value. + * + * @param p The value to be true to return the given value. + * @param a the value to return in an optional value if the given boolean is true. + * @return An optional value that has a value of the given argument if the given boolean is true, otherwise, returns + * no value. + */ + public static Option iif(final boolean p, final P1 a) { + return p ? some(a._1()) : Option.none(); + } + + /** + * Returns an optional value that has a value of the given argument if the given boolean is true, otherwise, returns + * no value. + * + * @param p The value to be true to return the given value. + * @param a the value to return in an optional value if the given boolean is true. + * @return An optional value that has a value of the given argument if the given boolean is true, otherwise, returns + * no value. + */ + public static Option iif(final boolean p, final A a) { + return iif(p, p(a)); + } + + /** + * First-class version of the iif function. + * + * @return a function that returns an optional value that has a value of the given argument, if the given predicate + * holds on that argument, or no value otherwise. + */ + public static F2, A, Option> iif() { + return new F2, A, Option>() { + public Option f(final F p, final A a) { + return iif(p, a); + } + }; + } + + /** + * Returns all the values in the given list. + * + * @param as The list of potential values to get actual values from. + * @return All the values in the given list. + */ + public static List somes(final List> as) { + return as.filter(Option.isSome_()).map(new F, A>() { + public A f(final Option o) { + return o.some(); + } + }); + } + + + /** + * Returns all the values in the given stream. + * + * @param as The stream of potential values to get actual values from. + * @return All the values in the given stream. + */ + public static Stream somes(final Stream> as) { + return as.filter(Option.isSome_()).map(new F, A>() { + public A f(final Option o) { + return o.some(); + } + }); + } + + /** + * Returns an optional non-empty string, or no value if the given string is empty. + * + * @param s A string to turn into an optional non-empty string. + * @return an optional non-empty string, or no value if the given string is empty. + */ + public static Option fromString(final String s) { + return fromNull(s).bind(new F>() { + public Option f(final String s) { + final Option none = none(); + return s.length() == 0 ? none : some(s); + } + }); + } + + /** + * Returns a function that transforms a string to an optional non-empty string, + * or no value if the string is empty. + * + * @return a function that transforms a string to an optional non-empty string, + * or no value if the string is empty. + */ + public static F> fromString() { + return new F>() { + public Option f(final String s) { + return fromString(s); + } + }; + } + + /** + * Returns a function that takes an optional value to a value or errors if there is no value. + * + * @return A function that takes an optional value to a value or errors if there is no value. + */ + public static F, A> fromSome() { + return new F, A>() { + public A f(final Option option) { + return option.some(); + } + }; + } + + /** + * Promotes a function of arity-2 so that it operates over options. + * + * @param f A function to promote. + * @return The given function promoted to operate on options. + */ + public static F, F, Option>> liftM2(final F> f) { + return curry(new F2, Option, Option>() { + public Option f(final Option a, final Option b) { + return a.bind(b, f); + } + }); + } + + /** + * First-class bind function. + * + * @return A function that binds a given function across an option with a final join. + */ + public static F>, F, Option>> bind() { + return curry(new F2>, Option, Option>() { + public Option f(final F> f, final Option a) { + return a.bind(f); + } + }); + } + + /** + * First-class join function. + * + * @return A function that joins an Option of an Option to make a single Option. + */ + public static F>, Option> join() { + return new F>, Option>() { + public Option f(final Option> option) { + return join(option); + } + }; + } + + /** + * A function that parses a string to a byte. + */ + public static final F> parseByte = new F>() { + public Option f(final String s) { + return parseByte(s).toOption(); + } + }; + + /** + * A function that parses a string to a double. + */ + public static final F> parseDouble = new F>() { + public Option f(final String s) { + return parseDouble(s).toOption(); + } + }; + + /** + * A function that parses a string to a float. + */ + public static final F> parseFloat = new F>() { + public Option f(final String s) { + return parseFloat(s).toOption(); + } + }; + + /** + * A function that parses a string to an integer. + */ + public static final F> parseInt = new F>() { + public Option f(final String s) { + return parseInt(s).toOption(); + } + }; + + /** + * A function that parses a string to a long. + */ + public static final F> parseLong = new F>() { + public Option f(final String s) { + return parseLong(s).toOption(); + } + }; + + /** + * A function that parses a string to a short. + */ + public static final F> parseShort = new F>() { + public Option f(final String s) { + return parseShort(s).toOption(); + } + }; +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Reader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Reader.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,50 @@ +package fj.data; + +import fj.F; +import fj.F1Functions; + +/** + * The Reader monad (also called the function monad, so equivalent to the idea of F). + * Created by MarkPerry on 7/07/2014. + */ +public class Reader { + + private F function; + + public Reader(F f) { + function = f; + } + + public F getFunction() { + return function; + } + + public static Reader unit(F f) { + return new Reader(f); + } + + public static Reader constant(B b) { + return unit(a -> b); + } + + public B f(A a) { + return function.f(a); + } + + public Reader map(F f) { + return unit(F1Functions.andThen(function, f)); + } + + public Reader andThen(F f) { + return map(f); + } + + public Reader flatMap(F> f) { + return unit(a -> f.f(function.f(a)).f(a)); + } + + public Reader bind(F> f) { + return flatMap(f); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/SafeIO.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/SafeIO.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,14 @@ +package fj.data; + +import java.io.IOException; + +/** + * Created by MarkPerry on 3/07/2014. + */ +public interface SafeIO extends IO { + + @Override + public A run(); + +} + diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Seq.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Seq.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,131 @@ +package fj.data; + +import fj.F; +import fj.F2; +import fj.Function; +import static fj.Bottom.error; +import static fj.Monoid.intAdditionMonoid; +import static fj.data.fingertrees.FingerTree.measured; + +import fj.data.fingertrees.FingerTree; +import fj.data.fingertrees.MakeTree; +import fj.data.fingertrees.Measured; + +/** + * Provides an immutable finite sequence, implemented as a finger tree. This structure gives O(1) access to + * the head and tail, as well as O(log n) random access and concatenation of sequences. + */ +public final class Seq { + private static final Measured ELEM_MEASURED = measured(intAdditionMonoid, Function.constant(1)); + private static final MakeTree MK_TREE = FingerTree.mkTree(ELEM_MEASURED); + private static final Seq EMPTY = new Seq(MK_TREE.empty()); + + @SuppressWarnings("unchecked") + private static MakeTree mkTree() { + return (MakeTree) MK_TREE; + } + + private final FingerTree ftree; + + private Seq(final FingerTree ftree) { + this.ftree = ftree; + } + + @SuppressWarnings("unchecked") + private static Measured elemMeasured() { + return (Measured) ELEM_MEASURED; + } + + /** + * The empty sequence. + * + * @return A sequence with no elements. + */ + @SuppressWarnings("unchecked") + public static Seq empty() { + return (Seq) EMPTY; + } + + /** + * A singleton sequence. + * + * @param a The single element in the sequence. + * @return A new sequence with the given element in it. + */ + public static Seq single(final A a) { + return new Seq(Seq.mkTree().single(a)); + } + + /** + * Inserts the given element at the front of this sequence. + * + * @param a An element to insert at the front of this sequence. + * @return A new sequence with the given element at the front. + */ + public Seq cons(final A a) { + return new Seq(ftree.cons(a)); + } + + /** + * Inserts the given element at the end of this sequence. + * + * @param a An element to insert at the end of this sequence. + * @return A new sequence with the given element at the end. + */ + public Seq snoc(final A a) { + return new Seq(ftree.snoc(a)); + } + + /** + * Appends the given sequence to this sequence. + * + * @param as A sequence to append to this one. + * @return A new sequence with the given sequence appended to this one. + */ + public Seq append(final Seq as) { + return new Seq(ftree.append(as.ftree)); + } + + /** + * Checks if this is the empty sequence. + * + * @return True if this sequence is empty, otherwise false. + */ + public boolean isEmpty() { + return ftree.isEmpty(); + } + + /** + * Returns the number of elements in this sequence. + * + * @return the number of elements in this sequence. + */ + public int length() { + return ftree.measure(); + } + + /** + * Returns the element at the given index. + * + * @param i The index of the element to return. + * @return The element at the given index, or throws an error if the index is out of bounds. + */ + public A index(final int i) { + if (i < 0 || i >= length()) + throw error("Index " + i + "out of bounds."); + return ftree.lookup(Function.identity(), i)._2(); + } + + public B foldLeft(final F2 f, final B z) { + return ftree.foldLeft(f, z); + } + + public B foldRight(final F2 f, final B z) { + return ftree.foldRight(f, z); + } + + public Seq map(F f) { + return new Seq(ftree.map(f, Seq.elemMeasured())); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Set.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Set.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,571 @@ +package fj.data; + +import fj.F; +import fj.F2; +import fj.Function; +import fj.Monoid; +import fj.Ord; +import fj.P; +import fj.P2; +import fj.P3; +import static fj.Function.*; +import static fj.data.Either.right; +import static fj.data.Option.some; +import static fj.function.Booleans.not; + +import fj.Ordering; +import static fj.Ordering.GT; +import static fj.Ordering.LT; + +import java.util.Iterator; + +/** + * Provides an in-memory, immutable set, implemented as a red/black tree. + */ +public abstract class Set implements Iterable { + private Set(final Ord ord) { + this.ord = ord; + } + + private enum Color { + R, B + } + + public final Ord ord; + + public final boolean isEmpty() { + return this instanceof Empty; + } + + @SuppressWarnings({ "ClassEscapesDefinedScope" }) + abstract Color color(); + + abstract Set l(); + + abstract A head(); + + abstract Set r(); + + /** + * Returns the order of this Set. + * + * @return the order of this Set. + */ + public final Ord ord() { + return ord; + } + + private static final class Empty extends Set { + private Empty(final Ord ord) { + super(ord); + } + + public Color color() { + return Color.B; + } + + public Set l() { + throw new Error("Left on empty set."); + } + + public Set r() { + throw new Error("Right on empty set."); + } + + public A head() { + throw new Error("Head on empty set."); + } + } + + private static final class Tree extends Set { + private final Color c; + private final Set a; + private final A x; + private final Set b; + + private Tree(final Ord ord, final Color c, final Set a, final A x, final Set b) { + super(ord); + this.c = c; + this.a = a; + this.x = x; + this.b = b; + } + + public Color color() { + return c; + } + + public Set l() { + return a; + } + + public A head() { + return x; + } + + public Set r() { + return b; + } + } + + /** + * Updates, with the given function, the first element in the set that is + * equal to the given element, according to the order. + * + * @param a + * An element to replace. + * @param f + * A function to transforms the found element. + * @return A pair of: (1) True if an element was found that matches the given + * element, otherwise false. (2) A new set with the given function + * applied to the first set element that was equal to the given + * element. + */ + public final P2> update(final A a, final F f) { + return isEmpty() ? P.p(false, this) : tryUpdate(a, f).either(new F>>() { + public P2> f(final A a2) { + return P.p(true, delete(a).insert(a2)); + } + }, Function.>> identity()); + } + + private Either>> tryUpdate(final A a, final F f) { + if (isEmpty()) + return right(P.p(false, this)); + else if (ord.isLessThan(a, head())) + return l().tryUpdate(a, f).right().map(new F>, P2>>() { + public P2> f(final P2> set) { + return set._1() ? P.p(true, (Set) new Tree(ord, color(), set._2(), head(), r())) : set; + } + }); + else if (ord.eq(a, head())) { + final A h = f.f(head()); + return ord.eq(head(), h) ? Either.>> right(P.p(true, (Set) new Tree(ord, color(), + l(), h, r()))) : Either.>> left(h); + } else + return r().tryUpdate(a, f).right().map(new F>, P2>>() { + public P2> f(final P2> set) { + return set._1() ? P.p(true, (Set) new Tree(ord, color(), l(), head(), set._2())) : set; + } + }); + } + + /** + * The empty set. + * + * @param ord + * An order for the type of elements. + * @return the empty set. + */ + public static Set empty(final Ord ord) { + return new Empty(ord); + } + + /** + * Checks if the given element is a member of this set. + * + * @param x + * An element to check for membership in this set. + * @return true if the given element is a member of this set. + */ + public final boolean member(final A x) { + return !isEmpty() && (ord.isLessThan(x, head()) ? l().member(x) : ord.eq(head(), x) || r().member(x)); + } + + /** + * First-class membership check. + * + * @return A function that returns true if the given element if a member of + * the given set. + */ + public static F, F> member() { + return curry(new F2, A, Boolean>() { + public Boolean f(final Set s, final A a) { + return s.member(a); + } + }); + } + + /** + * Inserts the given element into this set. + * + * @param x + * An element to insert into this set. + * @return A new set with the given element inserted. + */ + public final Set insert(final A x) { + return ins(x).makeBlack(); + } + + /** + * First-class insertion function. + * + * @return A function that inserts a given element into a given set. + */ + public static F, Set>> insert() { + return curry(new F2, Set>() { + public Set f(final A a, final Set set) { + return set.insert(a); + } + }); + } + + private Set ins(final A x) { + return isEmpty() ? new Tree(ord, Color.R, empty(ord), x, empty(ord)) : ord.isLessThan(x, head()) ? balance(ord, + color(), l().ins(x), head(), r()) : ord.eq(x, head()) ? new Tree(ord, color(), l(), x, r()) : balance(ord, + color(), l(), head(), r().ins(x)); + } + + private Set makeBlack() { + return new Tree(ord, Color.B, l(), head(), r()); + } + + @SuppressWarnings({ "SuspiciousNameCombination" }) + private static Tree tr(final Ord o, final Set a, final A x, final Set b, final A y, final Set c, + final A z, final Set d) { + return new Tree(o, Color.R, new Tree(o, Color.B, a, x, b), y, new Tree(o, Color.B, c, z, d)); + } + + private static Set balance(final Ord ord, final Color c, final Set l, final A h, final Set r) { + return c == Color.B && l.isTR() && l.l().isTR() ? tr(ord, l.l().l(), l.l().head(), l.l().r(), l.head(), l.r(), h, r) + : c == Color.B && l.isTR() && l.r().isTR() ? tr(ord, l.l(), l.head(), l.r().l(), l.r().head(), l.r().r(), h, r) + : c == Color.B && r.isTR() && r.l().isTR() ? tr(ord, l, h, r.l().l(), r.l().head(), r.l().r(), r.head(), + r.r()) : c == Color.B && r.isTR() && r.r().isTR() ? tr(ord, l, h, r.l(), r.head(), r.r().l(), r.r() + .head(), r.r().r()) : new Tree(ord, c, l, h, r); + } + + private boolean isTR() { + return !isEmpty() && color() == Color.R; + } + + /** + * Returns an iterator over this set. + * + * @return an iterator over this set. + */ + public final Iterator iterator() { + return toStream().iterator(); + } + + /** + * Returns a set with a single element. + * + * @param o + * An order for the type of element. + * @param a + * An element to put in a set. + * @return A new set with the given element in it. + */ + public static Set single(final Ord o, final A a) { + return empty(o).insert(a); + } + + /** + * Maps the given function across this set. + * + * @param o + * An order for the elements of the new set. + * @param f + * A function to map across this set. + * @return The set of the results of applying the given function to the + * elements of this set. + */ + public final Set map(final Ord o, final F f) { + return iterableSet(o, toStream().map(f)); + } + + /** + * Folds this Set using the given monoid. + * + * @param f + * A transformation from this Set's elements, to the monoid. + * @param m + * The monoid to fold this Set with. + * @return The result of folding the Set with the given monoid. + */ + public final B foldMap(final F f, final Monoid m) { + return isEmpty() ? m.zero() : m.sum(m.sum(r().foldMap(f, m), f.f(head())), l().foldMap(f, m)); + } + + /** + * Returns a list representation of this set. + * + * @return a list representation of this set. + */ + public final List toList() { + return foldMap(List.cons(List. nil()), Monoid. listMonoid()); + } + + /** + * Returns a stream representation of this set. + * + * @return a stream representation of this set. + */ + public final Stream toStream() { + return foldMap(Stream. single(), Monoid. streamMonoid()); + } + + /** + * Binds the given function across this set. + * + * @param o + * An order for the elements of the target set. + * @param f + * A function to bind across this set. + * @return A new set after applying the given function and joining the + * resulting sets. + */ + public final Set bind(final Ord o, final F> f) { + return join(o, map(Ord.setOrd(o), f)); + } + + /** + * Add all the elements of the given set to this set. + * + * @param s + * A set to add to this set. + * @return A new set containing all elements of both sets. + */ + public final Set union(final Set s) { + return iterableSet(ord, s.toStream().append(toStream())); + } + + /** + * A first class function for {@link #union(Set)}. + * + * @return A function that adds all the elements of one set to another set. + * @see #union(Set) + */ + public static F, F, Set>> union() { + return curry(new F2, Set, Set>() { + public Set f(final Set s1, final Set s2) { + return s1.union(s2); + } + }); + } + + /** + * Filters elements from this set by returning only elements which produce + * true when the given function is applied to them. + * + * @param f + * The predicate function to filter on. + * @return A new set whose elements all match the given predicate. + */ + public final Set filter(final F f) { + return iterableSet(ord, toStream().filter(f)); + } + + /** + * Deletes the given element from this set. + * + * @param a + * an element to remove. + * @return A new set containing all the elements of this set, except the given + * element. + */ + public final Set delete(final A a) { + return minus(single(ord, a)); + } + + /** + * First-class deletion function. + * + * @return A function that deletes a given element from a given set. + */ + public final F, Set>> delete() { + return curry(new F2, Set>() { + public Set f(final A a, final Set set) { + return set.delete(a); + } + }); + } + + /** + * Remove all elements from this set that do not occur in the given set. + * + * @param s + * A set of elements to retain. + * @return A new set which is the intersection of this set and the given set. + */ + public final Set intersect(final Set s) { + return filter(Set. member().f(s)); + } + + /** + * A first class function for {@link #intersect(Set)}. + * + * @return A function that intersects two given sets. + * @see #intersect(Set) + */ + public static F, F, Set>> intersect() { + return curry(new F2, Set, Set>() { + public Set f(final Set s1, final Set s2) { + return s1.intersect(s2); + } + }); + } + + /** + * Remove all elements from this set that occur in the given set. + * + * @param s + * A set of elements to delete. + * @return A new set which contains only the elements of this set that do not + * occur in the given set. + */ + public final Set minus(final Set s) { + return filter(compose(not, Set. member().f(s))); + } + + /** + * A first class function for {@link #minus(Set)}. + * + * @return A function that removes all elements of one set from another set. + * @see #minus(Set) + */ + public static F, F, Set>> minus() { + return curry(new F2, Set, Set>() { + public Set f(final Set s1, final Set s2) { + return s1.minus(s2); + } + }); + } + + /** + * Returns the size of this set. + * + * @return The number of elements in this set. + */ + public final int size() { + final F one = constant(1); + return foldMap(one, Monoid.intAdditionMonoid); + } + + /** + * Splits this set at the given element. Returns a product-3 of: + *
    + *
  • A set containing all the elements of this set which are less than the + * given value.
  • + *
  • An option of a value equal to the given value, if one was found in this + * set, otherwise None. + *
  • A set containing all the elements of this set which are greater than + * the given value.
  • + *
+ * + * @param a + * A value at which to split this set. + * @return Two sets and an optional value, where all elements in the first set + * are less than the given value and all the elements in the second + * set are greater than the given value, and the optional value is the + * given value if found, otherwise None. + */ + public final P3, Option
, Set> split(final A a) { + if (isEmpty()) + return P.p(empty(ord), Option. none(), empty(ord)); + else { + final A h = head(); + + final Ordering i = ord.compare(a, h); + + if (i == LT) { + final P3, Option, Set> lg = l().split(a); + Set lg1 = lg._1(); + Option lg2 = lg._2(); + Set lg3 = lg._3(); + Set lg4 = lg3.insert(h); + Set right = r(); + Set lg5 = lg4.union(right); + return P.p(lg1, lg2, lg5); + } else if (i == GT) { + final P3, Option, Set> lg = r().split(a); + return P.p(lg._1().insert(h).union(l()), lg._2(), lg._3()); + } else + return P.p(l(), some(h), r()); + } + } + + public final Option mapGet(final A a) { + if (isEmpty()) + return Option. none(); + else { + final A h = head(); + + final Ordering i = ord.compare(a, h); + + if (i == LT) { + Option lg = l().mapGet(a); + return lg; + } else if (i == GT) { + Option lg = r().mapGet(a); + return lg; + } else + return some(h); + } + } + + + + /** + * Returns true if this set is a subset of the given set. + * + * @param s + * A set which is a superset of this set if this method returns true. + * @return true if this set is a subset of the given set. + */ + public final boolean subsetOf(final Set s) { + if (isEmpty() || s.isEmpty()) + return isEmpty(); + else { + final P3, Option, Set> find = s.split(head()); + return find._2().isSome() && l().subsetOf(find._1()) && r().subsetOf(find._3()); + } + } + + /** + * Join a set of sets into a single set. + * + * @param s + * A set of sets. + * @param o + * An order for the elements of the new set. + * @return A new set which is the join of the given set of sets. + */ + public static Set join(final Ord o, final Set> s) { + final F, Set> id = identity(); + return s.foldMap(id, Monoid. setMonoid(o)); + } + + /** + * Return the elements of the given iterable as a set. + * + * @param o + * An order for the elements of the new set. + * @param as + * An iterable of elements to add to a set. + * @return A new set containing the elements of the given iterable. + */ + public static Set iterableSet(final Ord o, final Iterable as) { + Set s = empty(o); + for (final A a : as) + s = s.insert(a); + return s; + } + + /** + * Constructs a set from the given elements. + * + * @param o + * An order for the elements of the new set. + * @param as + * The elements to add to a set. + * @return A new set containing the elements of the given iterable. + */ + public static Set set(final Ord o, final A... as) { + Set s = empty(o); + for (final A a : as) + s = s.insert(a); + return s; + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/State.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/State.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,120 @@ +package fj.data; + +import fj.*; + +import java.util.*; + +import static fj.P.p; + +/** + * Created by MarkPerry on 7/07/2014. + */ +public class State { + + private F> run; + + private State(F> f) { + run = f; + } + + public P2 run(S s) { + return run.f(s); + } + + public static State unit(F> f) { + return new State(f); + } + + public static State units(F f) { + return unit((S s) -> { + S s2 = f.f(s); + return p(s2, s2); + }); + } + + public static State constant(A a) { + return unit(s -> p(s, a)); + } + + public State map(F f) { + return unit((S s) -> { + P2 p2 = run(s); + B b = f.f(p2._2()); + return p(p2._1(), b); + }); + } + + public static State modify(F f) { + return State.init().flatMap(s -> unit(s2 -> p(f.f(s), Unit.unit()))); + } + + public State mapState(F, P2> f) { + return unit(s -> f.f(run(s))); + } + + public static State flatMap(State mb, F> f) { + return mb.flatMap(f); + } + + public State flatMap(F> f) { + return unit((S s) -> { + P2 p = run(s); + A a = p._2(); + S s2 = p._1(); + State smb = f.f(a); + return smb.run(s2); + }); + } + + public static State init() { + return unit(s -> p(s, s)); + } + + public State gets() { + return unit(s -> { + P2 p = run(s); + S s2 = p._1(); + return p(s2, s2); + }); + } + + public static State put(S s) { + return State.unit((S z) -> p(s, Unit.unit())); + } + + public A eval(S s) { + return run(s)._2(); + } + + public S exec(S s) { + return run(s)._1(); + } + + public State withs(F f) { + return unit(F1Functions.andThen(f, run)); + } + + public static State gets(F f) { + return State.init().map(s -> f.f(s)); + } + + /** + * Evaluate each action in the sequence from left to right, and collect the results. + */ + public static State> sequence(List> list) { + return list.foldLeft((State> acc, State ma) -> + acc.flatMap((List xs) -> ma.map((A x) -> xs.snoc(x)) + ), constant(List.nil())); + } + + /** + * Map each element of a structure to an action, evaluate these actions from left to right + * and collect the results. + */ + public static State> traverse(List list, F> f) { + return list.foldLeft((State> acc, A a) -> + acc.flatMap(bs -> f.f(a).map(b -> bs.snoc(b)) + ), constant(List.nil())); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Stream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Stream.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,1809 @@ +package fj.data; + +import fj.Effect; +import fj.Equal; +import fj.F; +import fj.F2; +import fj.F3; +import fj.Function; +import fj.Monoid; +import fj.Ord; +import fj.P; +import fj.P1; +import fj.P2; +import fj.Unit; +import fj.control.parallel.Promise; +import fj.control.parallel.Strategy; +import fj.Ordering; +import fj.function.Effect1; + +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import static fj.Bottom.error; +import static fj.Function.compose; +import static fj.Function.constant; +import static fj.Function.curry; +import static fj.Function.flip; +import static fj.Function.identity; +import static fj.P.p; +import static fj.P.p2; +import static fj.Unit.unit; +import static fj.control.parallel.Promise.promise; +import static fj.data.Array.mkArray; +import static fj.data.Option.none; +import static fj.data.Option.some; +import static fj.function.Booleans.not; +import static fj.Ordering.EQ; +import static fj.Ordering.GT; +import static fj.Ordering.LT; + +/** + * A lazy (not yet evaluated), immutable, singly linked list. + * + * @version %build.number% + */ +public abstract class Stream implements Iterable { + private Stream() { + + } + + /** + * Returns an iterator for this stream. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this stream. + */ + public final Iterator iterator() { + return toCollection().iterator(); + } + + /** + * The first element of the stream or fails for the empty stream. + * + * @return The first element of the stream or fails for the empty stream. + */ + public abstract A head(); + + /** + * The stream without the first element or fails for the empty stream. + * + * @return The stream without the first element or fails for the empty stream. + */ + public abstract P1> tail(); + + /** + * Returns true if this stream is empty, false otherwise. + * + * @return true if this stream is empty, false otherwise. + */ + public final boolean isEmpty() { + return this instanceof Nil; + } + + /** + * Returns false if this stream is empty, true otherwise. + * + * @return false if this stream is empty, true otherwise. + */ + public final boolean isNotEmpty() { + return this instanceof Cons; + } + + /** + * Performs a reduction on this stream using the given arguments. + * + * @param nil The value to return if this stream is empty. + * @param cons The function to apply to the head and tail of this stream if it is not empty. + * @return A reduction on this stream. + */ + public final B stream(final B nil, final F>, B>> cons) { + return isEmpty() ? nil : cons.f(head()).f(tail()); + } + + /** + * Performs a right-fold reduction across this stream. This function uses O(length) stack space. + * + * @param f The function to apply on each element of the stream. + * @param b The beginning value to start the application from. + * @return The final result after the right-fold reduction. + */ + public final B foldRight(final F, B>> f, final B b) { + return isEmpty() ? b : f.f(head()).f(new P1() { + public B _1() { + return tail()._1().foldRight(f, b); + } + }); + } + + /** + * Performs a right-fold reduction across this stream. This function uses O(length) stack space. + * + * @param f The function to apply on each element of the stream. + * @param b The beginning value to start the application from. + * @return The final result after the right-fold reduction. + */ + public final B foldRight(final F2, B> f, final B b) { + return foldRight(curry(f), b); + } + + /** + * Performs a right-fold reduction across this stream. This function uses O(length) stack space. + * + * @param f The function to apply on each element of the stream. + * @param b The beginning value to start the application from. + * @return The final result after the right-fold reduction. + */ + public final B foldRight1(final F> f, final B b) { + return foldRight(compose(Function., B, B>andThen().f(P1.__1()), f), b); + } + + /** + * Performs a right-fold reduction across this stream. This function uses O(length) stack space. + * + * @param f The function to apply on each element of the stream. + * @param b The beginning value to start the application from. + * @return The final result after the right-fold reduction. + */ + public final B foldRight1(final F2 f, final B b) { + return foldRight1(curry(f), b); + } + + /** + * Performs a left-fold reduction across this stream. This function runs in constant space. + * + * @param f The function to apply on each element of the stream. + * @param b The beginning value to start the application from. + * @return The final result after the left-fold reduction. + */ + public final B foldLeft(final F> f, final B b) { + B x = b; + + for (Stream xs = this; !xs.isEmpty(); xs = xs.tail()._1()) + x = f.f(x).f(xs.head()); + + return x; + } + + /** + * Performs a left-fold reduction across this stream. This function runs in constant space. + * + * @param f The function to apply on each element of the stream. + * @param b The beginning value to start the application from. + * @return The final result after the left-fold reduction. + */ + public final B foldLeft(final F2 f, final B b) { + return foldLeft(curry(f), b); + } + + /** + * Takes the first 2 elements of the stream and applies the function to them, + * then applies the function to the result and the third element and so on. + * + * @param f The function to apply on each element of the stream. + * @return The final result after the left-fold reduction. + */ + public final A foldLeft1(final F2 f) { + return foldLeft1(curry(f)); + } + + /** + * Takes the first 2 elements of the stream and applies the function to them, + * then applies the function to the result and the third element and so on. + * + * @param f The function to apply on each element of the stream. + * @return The final result after the left-fold reduction. + */ + public final A foldLeft1(final F> f) { + if (isEmpty()) + throw error("Undefined: foldLeft1 on empty list"); + return tail()._1().foldLeft(f, head()); + } + + /** + * Returns the head of this stream if there is one or the given argument if this stream is empty. + * + * @param a The argument to return if this stream is empty. + * @return The head of this stream if there is one or the given argument if this stream is empty. + */ + public final A orHead(final P1 a) { + return isEmpty() ? a._1() : head(); + } + + /** + * Returns the tail of this stream if there is one or the given argument if this stream is empty. + * + * @param as The argument to return if this stream is empty. + * @return The tail of this stream if there is one or the given argument if this stream is empty. + */ + public final P1> orTail(final P1> as) { + return isEmpty() ? as : tail(); + } + + /** + * Intersperses the given value between each two elements of the stream. + * + * @param a The value to intersperse between values of the stream. + * @return A new stream with the given value between each two elements of the stream. + */ + public final Stream intersperse(final A a) { + return isEmpty() ? this : cons(head(), new P1>() { + public Stream _1() { + return prefix(a, tail()._1()); + } + + public Stream prefix(final A x, final Stream xs) { + return xs.isEmpty() ? xs : cons(x, p(cons(xs.head(), new P1>() { + public Stream _1() { + return prefix(a, xs.tail()._1()); + } + }))); + } + }); + } + + /** + * Maps the given function across this stream. + * + * @param f The function to map across this stream. + * @return A new stream after the given function has been applied to each element. + */ + public final Stream map(final F f) { + return isEmpty() ? Stream.nil() : cons(f.f(head()), new P1>() { + public Stream _1() { + return tail()._1().map(f); + } + }); + } + + /** + * Provides a first-class version of the map function. + * + * @return A function that maps a given function across a given stream. + */ + public static F, F, Stream>> map_() { + return new F, F, Stream>>() { + public F, Stream> f(final F f) { + return new F, Stream>() { + public Stream f(final Stream as) { + return as.map(f); + } + }; + } + }; + } + + /** + * Performs a side-effect for each element of this stream. + * + * @param f The side-effect to perform for the given element. + * @return The unit value. + */ + public final Unit foreach(final F f) { + for (Stream xs = this; xs.isNotEmpty(); xs = xs.tail()._1()) + f.f(xs.head()); + + return unit(); + } + + /** + * Performs a side-effect for each element of this stream. + * + * @param f The side-effect to perform for the given element. + */ + public final void foreachDoEffect(final Effect1 f) { + for (Stream xs = this; xs.isNotEmpty(); xs = xs.tail()._1()) + f.f(xs.head()); + } + + /** + * Filters elements from this stream by returning only elements which produce true + * when the given function is applied to them. + * + * @param f The predicate function to filter on. + * @return A new stream whose elements all match the given predicate. + */ + public final Stream filter(final F f) { + final Stream as = dropWhile(not(f)); + return as.isNotEmpty() ? cons(as.head(), new P1>() { + public Stream _1() { + return as.tail()._1().filter(f); + } + }) : as; + } + + /** + * Appends the given stream to this stream. + * + * @param as The stream to append to this one. + * @return A new stream that has appended the given stream. + */ + public final Stream append(final Stream as) { + return isEmpty() ? as : cons(head(), new P1>() { + public Stream _1() { + return tail()._1().append(as); + } + }); + } + + /** + * Appends the given stream to this stream. + * + * @param as The stream to append to this one. + * @return A new stream that has appended the given stream. + */ + public final Stream append(final P1> as) { + return isEmpty() ? as._1() : cons(head(), new P1>() { + public Stream _1() { + return tail()._1().append(as); + } + }); + } + + /** + * Returns a new stream of all the items in this stream that do not appear in the given stream. + * + * @param eq an equality for the items of the streams. + * @param xs a list to subtract from this stream. + * @return a stream of all the items in this stream that do not appear in the given stream. + */ + public final Stream minus(final Equal eq, final Stream xs) { + return removeAll(compose(Monoid.disjunctionMonoid.sumLeftS(), xs.mapM(curry(eq.eq())))); + } + + /** + * Filters elements from this stream by returning only elements which produce false when + * the given function is applied to them. + * + * @param f The predicate function to filter on. + * @return A new stream whose elements do not match the given predicate. + */ + public final Stream removeAll(final F f) { + return filter(compose(not, f)); + } + + /** + * Turn a stream of functions into a function returning a stream. + * + * @param fs The stream of functions to sequence into a single function that returns a stream. + * @return A function that, when given an argument, applies all the functions in the given stream to it + * and returns a stream of the results. + */ + public static F> sequence_(final Stream> fs) { + return fs.foldRight(new F2, P1>>, F>>() { + public F> f(final F baf, final P1>> p1) { + return Function.bind(baf, p1._1(), Function.curry(new F2, Stream>() { + public Stream f(final A a, final Stream stream) { + return cons(a, p(stream)); + } + })); + } + }, Function + .>constant(Stream.nil())); + } + + /** + * Maps the given function of arity-2 across this stream and returns a function that applies all the resulting + * functions to a given argument. + * + * @param f A function of arity-2 + * @return A function that, when given an argument, applies the given function to that argument and every element + * in this list. + */ + public final F> mapM(final F> f) { + return sequence_(map(f)); + } + + /** + * Binds the given function across each element of this stream with a final join. + * + * @param f The function to apply to each element of this stream. + * @return A new stream after performing the map, then final join. + */ + public final Stream bind(final F> f) { + return map(f).foldLeft(new F2, Stream, Stream>() { + @Override + public Stream f(Stream accumulator, Stream element) { + Stream result = accumulator; + for (B single : element) { + result = result.cons(single); + } + return result; + } + }, Stream.nil()).reverse(); + } + + /** + * Binds the given function across each element of this stream and the given stream with a final + * join. + * + * @param sb A given stream to bind the given function with. + * @param f The function to apply to each element of this stream and the given stream. + * @return A new stream after performing the map, then final join. + */ + public final Stream bind(final Stream sb, final F> f) { + return sb.apply(map(f)); + } + + /** + * Binds the given function across each element of this stream and the given stream with a final + * join. + * + * @param sb A given stream to bind the given function with. + * @param f The function to apply to each element of this stream and the given stream. + * @return A new stream after performing the map, then final join. + */ + public final Stream bind(final Stream sb, final F2 f) { + return bind(sb, curry(f)); + } + + /** + * Binds the given function across each element of this stream and the given streams with a final + * join. + * + * @param sb A given stream to bind the given function with. + * @param sc A given stream to bind the given function with. + * @param f The function to apply to each element of this stream and the given streams. + * @return A new stream after performing the map, then final join. + */ + public final Stream bind(final Stream sb, final Stream sc, final F>> f) { + return sc.apply(bind(sb, f)); + } + + /** + * Binds the given function across each element of this stream and the given streams with a final + * join. + * + * @param sb A given stream to bind the given function with. + * @param sc A given stream to bind the given function with. + * @param sd A given stream to bind the given function with. + * @param f The function to apply to each element of this stream and the given streams. + * @return A new stream after performing the map, then final join. + */ + public final Stream bind(final Stream sb, final Stream sc, final Stream sd, + final F>>> f) { + return sd.apply(bind(sb, sc, f)); + } + + /** + * Binds the given function across each element of this stream and the given streams with a final + * join. + * + * @param sb A given stream to bind the given function with. + * @param sc A given stream to bind the given function with. + * @param sd A given stream to bind the given function with. + * @param se A given stream to bind the given function with. + * @param f The function to apply to each element of this stream and the given streams. + * @return A new stream after performing the map, then final join. + */ + public final Stream bind(final Stream sb, final Stream sc, final Stream sd, + final Stream se, final F>>>> f) { + return se.apply(bind(sb, sc, sd, f)); + } + + /** + * Binds the given function across each element of this stream and the given streams with a final + * join. + * + * @param sb A given stream to bind the given function with. + * @param sc A given stream to bind the given function with. + * @param sd A given stream to bind the given function with. + * @param se A given stream to bind the given function with. + * @param sf A given stream to bind the given function with. + * @param f The function to apply to each element of this stream and the given streams. + * @return A new stream after performing the map, then final join. + */ + public final Stream bind(final Stream sb, final Stream sc, final Stream sd, + final Stream se, final Stream sf, + final F>>>>> f) { + return sf.apply(bind(sb, sc, sd, se, f)); + } + + /** + * Binds the given function across each element of this stream and the given streams with a final + * join. + * + * @param sb A given stream to bind the given function with. + * @param sc A given stream to bind the given function with. + * @param sd A given stream to bind the given function with. + * @param se A given stream to bind the given function with. + * @param sf A given stream to bind the given function with. + * @param sg A given stream to bind the given function with. + * @param f The function to apply to each element of this stream and the given streams. + * @return A new stream after performing the map, then final join. + */ + public final Stream bind(final Stream sb, final Stream sc, final Stream sd, + final Stream se, final Stream sf, final Stream sg, + final F>>>>>> f) { + return sg.apply(bind(sb, sc, sd, se, sf, f)); + } + + /** + * Binds the given function across each element of this stream and the given streams with a final + * join. + * + * @param sb A given stream to bind the given function with. + * @param sc A given stream to bind the given function with. + * @param sd A given stream to bind the given function with. + * @param se A given stream to bind the given function with. + * @param sf A given stream to bind the given function with. + * @param sg A given stream to bind the given function with. + * @param sh A given stream to bind the given function with. + * @param f The function to apply to each element of this stream and the given streams. + * @return A new stream after performing the map, then final join. + */ + public final Stream bind(final Stream sb, final Stream sc, final Stream sd, + final Stream se, final Stream sf, final Stream sg, + final Stream sh, + final F>>>>>>> f) { + return sh.apply(bind(sb, sc, sd, se, sf, sg, f)); + } + + /** + * Performs a bind across each stream element, but ignores the element value each time. + * + * @param bs The stream to apply in the final join. + * @return A new stream after the final join. + */ + public final Stream sequence(final Stream bs) { + final F> c = constant(bs); + return bind(c); + } + + /** + * Performs function application within a stream (applicative functor pattern). + * + * @param sf The stream of functions to apply. + * @return A new stream after applying the given stream of functions through this stream. + */ + public final Stream apply(final Stream> sf) { + return sf.bind(new F, Stream>() { + public Stream f(final F f) { + return map(new F() { + public B f(final A a) { + return f.f(a); + } + }); + } + }); + } + + /** + * Interleaves the given stream with this stream to produce a new stream. + * + * @param as The stream to interleave this stream with. + * @return A new stream with elements interleaved from this stream and the given stream. + */ + public final Stream interleave(final Stream as) { + return isEmpty() ? as : as.isEmpty() ? this : cons(head(), new P1>() { + @Override public Stream _1() { + return as.interleave(tail()._1()); + } + }); + } + + /** + * Sort this stream according to the given ordering. + * + * @param o An ordering for the elements of this stream. + * @return A new stream with the elements of this stream sorted according to the given ordering. + */ + public final Stream sort(final Ord o) { + return mergesort(o, map(flip(Stream.cons()).f(p(Stream.nil())))); + } + + // Merges a stream of individually sorted streams into a single sorted stream. + private static Stream mergesort(final Ord o, final Stream> s) { + if (s.isEmpty()) + return nil(); + Stream> xss = s; + while (xss.tail()._1().isNotEmpty()) + xss = mergePairs(o, xss); + return xss.head(); + } + + // Merges individually sorted streams two at a time. + private static Stream> mergePairs(final Ord o, final Stream> s) { + if (s.isEmpty() || s.tail()._1().isEmpty()) + return s; + final Stream> t = s.tail()._1(); + return cons(merge(o, s.head(), t.head()), new P1>>() { + public Stream> _1() { + return mergePairs(o, t.tail()._1()); + } + }); + } + + // Merges two individually sorted streams. + private static Stream merge(final Ord o, final Stream xs, final Stream ys) { + if (xs.isEmpty()) + return ys; + if (ys.isEmpty()) + return xs; + final A x = xs.head(); + final A y = ys.head(); + if (o.isGreaterThan(x, y)) + return cons(y, new P1>() { + public Stream _1() { + return merge(o, xs, ys.tail()._1()); + } + }); + return cons(x, new P1>() { + public Stream _1() { + return merge(o, xs.tail()._1(), ys); + } + }); + } + + /** + * Sort this stream according to the given ordering, using a parallel Quick Sort algorithm that uses the given + * parallelisation strategy. + * + * @param o An ordering for the elements of this stream. + * @param s A strategy for parallelising the algorithm. + * @return A new stream with the elements of this stream sorted according to the given ordering. + */ + public final Stream sort(final Ord o, final Strategy s) { + return qs(o, s).claim(); + } + + private Promise> qs(final Ord o, final Strategy s) { + if (isEmpty()) + return promise(s, P.p(this)); + else { + final F id = identity(); + final A x = head(); + final P1> xs = tail(); + final Promise> left = Promise.join(s, xs.map(flt(o, s, x, id))); + final Promise> right = xs.map(flt(o, s, x, not))._1(); + final Monoid> m = Monoid.streamMonoid(); + return right.fmap(m.sum(single(x))).apply(left.fmap(m.sum())); + } + } + + private static F, Promise>> qs_(final Ord o, final Strategy s) { + return new F, Promise>>() { + public Promise> f(final Stream xs) { + return xs.qs(o, s); + } + }; + } + + private static F, Promise>> flt(final Ord o, + final Strategy s, + final A x, + final F f) { + final F, F, Stream>> filter = filter(); + final F lt = o.isLessThan(x); + return compose(qs_(o, s), filter.f(compose(f, lt))); + } + + /** + * Projects an immutable collection of this stream. + * + * @return An immutable collection of this stream. + */ + public final Collection toCollection() { + return new AbstractCollection() { + public Iterator iterator() { + return new Iterator() { + private Stream xs = Stream.this; + + public boolean hasNext() { + return xs.isNotEmpty(); + } + + public A next() { + if (xs.isEmpty()) + throw new NoSuchElementException(); + else { + final A a = xs.head(); + xs = xs.tail()._1(); + return a; + } + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + public int size() { + return length(); + } + }; + } + + /** + * Returns a stream of integers from the given from value (inclusive) to the given + * to value (exclusive). + * + * @param from The minimum value for the stream (inclusive). + * @param to The maximum value for the stream (exclusive). + * @return A stream of integers from the given from value (inclusive) to the given + * to value (exclusive). + */ + public static Stream range(final int from, final long to) { + return from >= to ? Stream.nil() : cons(from, new P1>() { + public Stream _1() { + return range(from + 1, to); + } + }); + } + + /** + * Constructs a stream with the given elements. + * + * @param as The elements which which to construct a stream. + * @return a new stream with the given elements. + */ + public static Stream stream(final A... as) { + return as.length == 0 ? Stream.nil() + : unfold(P2.tuple(new F2>>>() { + public Option>> f(final A[] as, final Integer i) { + return i >= as.length ? Option.>>none() + : some(P.p(as[i], P.p(as, i + 1))); + } + }), P.p(as, 0)); + } + + /** + * Returns a stream that is either infinite or bounded up to the maximum value of the given iterator starting at the + * given value and stepping at increments of 1. + * + * @param e The enumerator to compute successors from. + * @param from The value to begin computing successors from. + * @return A stream that is either infinite or bounded up to the maximum value of the given iterator starting at the + * given value and stepping at increments of 1. + */ + public static Stream forever(final Enumerator e, final A from) { + return forever(e, from, 1L); + } + + /** + * Returns a stream that is either infinite or bounded up to the maximum value of the given iterator starting at the + * given value and stepping at the given increment. + * + * @param e The enumerator to compute successors from. + * @param from The value to begin computing successors from. + * @param step The increment to step. + * @return A stream that is either infinite or bounded up to the maximum value of the given iterator starting at the + * given value and stepping at the given increment. + */ + public static Stream forever(final Enumerator e, final A from, final long step) { + return cons(from, new P1>() { + public Stream _1() { + return e.plus(from, step).map(new F>() { + public Stream f(final A a) { + return forever(e, a, step); + } + }).orSome(Stream.nil()); + } + }); + } + + /** + * Returns a stream using the given enumerator from the given value to the other given value stepping at increments of + * 1. + * + * @param e The enumerator to compute successors from. + * @param from The value to begin computing successors from. + * @param to The value to stop computing successors from. + * @return A stream using the given enumerator from the given value to the other given value stepping at increments of + * 1. + */ + public static Stream range(final Enumerator e, final A from, final A to) { + return range(e, from, to, 1L); + } + + /** + * Returns a stream using the given enumerator from the given value to the other given value stepping at the given + * increment. + * + * @param e The enumerator to compute successors from. + * @param from The value to begin computing successors from. + * @param to The value to stop computing successors from. + * @param step The increment to step. + * @return A stream using the given enumerator from the given value to the other given value stepping at the given + * increment. + */ + public static Stream range(final Enumerator e, final A from, final A to, final long step) { + final Ordering o = e.order().compare(from, to); + return o == EQ || step > 0L && o == GT || step < 0L && o == LT ? single(from) : cons(from, new P1>() { + public Stream _1() { + return Stream.join(e.plus(from, step).filter(new F() { + public Boolean f(final A a) { + return !(o == LT ? e.order().isLessThan(to, a) : e.order().isGreaterThan(to, a)); + } + }).map(new F>() { + public Stream f(final A a) { + return range(e, a, to, step); + } + }).toStream()); + } + }); + } + + /** + * Returns an infinite stream of integers from the given from value (inclusive). + * + * @param from The minimum value for the stream (inclusive). + * @return A stream of integers from the given from value (inclusive). + */ + public static Stream range(final int from) { + return cons(from, new P1>() { + public Stream _1() { + return range(from + 1); + } + }); + } + + /** + * Returns a first-class version of the filter function. + * + * @return a function that filters a given stream using a given predicate. + */ + public static F, F, Stream>> filter() { + return curry(new F2, Stream, Stream>() { + public Stream f(final F f, final Stream as) { + return as.filter(f); + } + }); + } + + /** + * Zips this stream with the given stream of functions, applying each function in turn to the + * corresponding element in this stream to produce a new stream. If this stream and the given stream + * have different lengths, then the longer stream is normalised so this function never fails. + * + * @param fs The stream of functions to apply to this stream. + * @return A new stream with a length the same as the shortest of this stream and the given stream. + */ + public final Stream zapp(final Stream> fs) { + return fs.isEmpty() || isEmpty() ? Stream.nil() : + cons(fs.head().f(head()), new P1>() { + public Stream _1() { + return tail()._1().zapp(fs.tail()._1()); + } + }); + } + + /** + * Zips this stream with the given stream using the given function to produce a new stream. If + * this stream and the given stream have different lengths, then the longer stream is normalised + * so this function never fails. + * + * @param bs The stream to zip this stream with. + * @param f The function to zip this stream and the given stream with. + * @return A new stream with a length the same as the shortest of this stream and the given + * stream. + */ + public final Stream zipWith(final Stream bs, final F> f) { + return bs.zapp(zapp(repeat(f))); + } + + /** + * Zips this stream with the given stream using the given function to produce a new stream. If + * this stream and the given stream have different lengths, then the longer stream is normalised + * so this function never fails. + * + * @param bs The stream to zip this stream with. + * @param f The function to zip this stream and the given stream with. + * @return A new stream with a length the same as the shortest of this stream and the given + * stream. + */ + public final Stream zipWith(final Stream bs, final F2 f) { + return zipWith(bs, curry(f)); + } + + /** + * Partially-applied version of zipWith. + * Returns a function that zips a given stream with this stream using the given function. + * + * @param f The function to zip this stream and a given stream with. + * @return A function that zips a given stream with this stream using the given function. + */ + public final F, Stream> zipWith(final F> f) { + return new F, Stream>() { + public Stream f(final Stream stream) { + return zipWith(stream, f); + } + }; + } + + /** + * Zips this stream with the given stream to produce a stream of pairs. If this stream and the + * given stream have different lengths, then the longer stream is normalised so this function + * never fails. + * + * @param bs The stream to zip this stream with. + * @return A new stream with a length the same as the shortest of this stream and the given + * stream. + */ + public final Stream> zip(final Stream bs) { + final F>> __2 = p2(); + return zipWith(bs, __2); + } + + /** + * Zips this stream with the index of its element as a pair. + * + * @return A new stream with the same length as this stream. + */ + public final Stream> zipIndex() { + return zipWith(range(0), new F2>() { + public P2 f(final A a, final Integer i) { + return p(a, i); + } + }); + } + + /** + * Returns an either projection of this stream; the given argument in Left if empty, + * or the first element in Right. + * + * @param x The value to return in left if this stream is empty. + * @return An either projection of this stream. + */ + public final Either toEither(final P1 x) { + return isEmpty() ? Either.left(x._1()) : Either.right(head()); + } + + /** + * Returns an option projection of this stream; None if empty, or the first element + * in Some. + * + * @return An option projection of this stream. + */ + public final Option toOption() { + return isEmpty() ? Option.none() : some(head()); + } + + /** + * Returns a list projection of this stream. + * + * @return A list projection of this stream. + */ + public final List toList() { + List as = List.nil(); + + for (Stream x = this; !x.isEmpty(); x = x.tail()._1()) { + as = as.snoc(x.head()); + } + + return as; + } + + + /** + * Returns a array projection of this stream. + * + * @return A array projection of this stream. + */ + @SuppressWarnings({"unchecked"}) + public final Array toArray() { + final int l = length(); + final Object[] a = new Object[l]; + Stream x = this; + for (int i = 0; i < l; i++) { + a[i] = x.head(); + x = x.tail()._1(); + } + + return mkArray(a); + } + + /** + * Returns a array projection of this stream. + * + * @param c The class type of the array to return. + * @return A array projection of this stream. + */ + @SuppressWarnings({"unchecked", "UnnecessaryFullyQualifiedName"}) + public final Array toArray(final Class c) { + final A[] a = (A[]) java.lang.reflect.Array.newInstance(c.getComponentType(), length()); + + int i = 0; + for (final A x : this) { + a[i] = x; + i++; + } + + return Array.array(a); + } + + /** + * Returns an array from this stream. + * + * @param c The class type of the array to return. + * @return An array from this stream. + */ + public final A[] array(final Class c) { + return toArray(c).array(c); + } + + /** + * Prepends (cons) the given element to this stream to product a new stream. + * + * @param a The element to prepend. + * @return A new stream with the given element at the head. + */ + public final Stream cons(final A a) { + return new Cons(a, new P1>() { + public Stream _1() { + return Stream.this; + } + }); + } + + /** + * Returns a string from the given stream of characters. The inverse of this function is {@link + * #fromString(String)}. + * + * @param cs The stream of characters to produce the string from. + * @return A string from the given stream of characters. + */ + public static String asString(final Stream cs) { + return LazyString.fromStream(cs).toString(); + } + + /** + * Returns a stream of characters from the given string. The inverse of this function is {@link + * #asString(Stream)}. + * + * @param s The string to produce the stream of characters from. + * @return A stream of characters from the given string. + */ + public static Stream fromString(final String s) { + return LazyString.str(s).toStream(); + } + + /** + * Append the given element to this stream to product a new stream. + * + * @param a The element to append. + * @return A new stream with the given element at the end. + */ + public final Stream snoc(final A a) { + return snoc(p(a)); + } + + /** + * Append the given element to this stream to produce a new stream. + * + * @param a The element to append. + * @return A new stream with the given element at the end. + */ + public final Stream snoc(final P1 a) { + return append(new P1>() { + public Stream _1() { + return single(a._1()); + } + }); + } + + /** + * Returns the first n elements from the head of this stream. + * + * @param n The number of elements to take from this stream. + * @return The first n elements from the head of this stream. + */ + public final Stream take(final int n) { + return n <= 0 || isEmpty() ? + Stream.nil() : + cons(head(), new P1>() { + public Stream _1() { + return tail()._1().take(n - 1); + } + }); + } + + /** + * Drops the given number of elements from the head of this stream if they are available. + * + * @param i The number of elements to drop from the head of this stream. + * @return A stream with a length the same, or less than, this stream. + */ + public final Stream drop(final int i) { + int c = 0; + + Stream xs = this; + + for (; xs.isNotEmpty() && c < i; xs = xs.tail()._1()) + c++; + + return xs; + } + + /** + * Returns the first elements of the head of this stream that match the given predicate function. + * + * @param f The predicate function to apply on this stream until it finds an element that does not + * hold, or the stream is exhausted. + * @return The first elements of the head of this stream that match the given predicate function. + */ + public final Stream takeWhile(final F f) { + return isEmpty() ? + this : + f.f(head()) ? + cons(head(), new P1>() { + public Stream _1() { + return tail()._1().takeWhile(f); + } + }) : + Stream.nil(); + } + + /** + * Removes elements from the head of this stream that do not match the given predicate function + * until an element is found that does match or the stream is exhausted. + * + * @param f The predicate function to apply through this stream. + * @return The stream whose first element does not match the given predicate function. + */ + public final Stream dropWhile(final F f) { + Stream as; + //noinspection StatementWithEmptyBody + for (as = this; !as.isEmpty() && f.f(as.head()); as = as.tail()._1()) ; + + return as; + } + + /** + * Returns a tuple where the first element is the longest prefix of this stream that satisfies + * the given predicate and the second element is the remainder of the stream. + * + * @param p A predicate to be satisfied by a prefix of this stream. + * @return A tuple where the first element is the longest prefix of this stream that satisfies + * the given predicate and the second element is the remainder of the stream. + */ + public final P2, Stream> span(final F p) { + if (isEmpty()) + return p(this, this); + else if (p.f(head())) { + final P1, Stream>> yszs = new P1, Stream>>() { + @Override public P2, Stream> _1() { + return tail()._1().span(p); + } + }; + return new P2, Stream>() { + @Override public Stream _1() { + return cons(head(), yszs.map(P2., Stream>__1())); + } + + @Override public Stream _2() { + return yszs._1()._2(); + } + }; + } else + return p(Stream.nil(), this); + } + + /** + * Returns a new stream resulting from replacing all elements that match the given predicate with the given element. + * + * @param p The predicate to match replaced elements. + * @param a The element with which to replace elements. + * @return A new stream resulting from replacing all elements that match the given predicate with the given element. + */ + public final Stream replace(final F p, final A a) { + if (isEmpty()) + return nil(); + else { + final P2, Stream> s = span(p); + return s._1().append(cons(a, new P1>() { + @Override public Stream _1() { + return s._2().tail()._1().replace(p, a); + } + })); + } + } + + /** + * Returns a tuple where the first element is the longest prefix of this stream that does not satisfy + * the given predicate and the second element is the remainder of the stream. + * + * @param p A predicate not to be satisfied by a prefix of this stream. + * @return A tuple where the first element is the longest prefix of this stream that does not satisfy + * the given predicate and the second element is the remainder of the stream. + */ + public final P2, Stream> split(final F p) { + return span(compose(not, p)); + } + + /** + * Reverse this stream in constant stack space. + * + * @return A new stream that is the reverse of this one. + */ + public final Stream reverse() { + return foldLeft(new F, F>>() { + public F> f(final Stream as) { + return new F>() { + public Stream f(final A a) { + return cons(a, new P1>() { + public Stream _1() { + return as; + } + }); + } + }; + } + }, Stream.nil()); + } + + /** + * Get the last element of this stream. Undefined for infinite streams. + * + * @return The last element in this stream, if there is one. + */ + public final A last() { + return reverse().head(); + } + + /** + * The length of this stream. This function will not terminate for an infinite stream. + * + * @return The length of this stream. + */ + public final int length() { + // we're using an iterative approach here as the previous implementation (toList().length()) took + // very long even for some 10000 elements. + Stream xs = this; + int i = 0; + while (!xs.isEmpty()) { + xs = xs.tail()._1(); + i += 1; + } + return i; + } + + /** + * Returns the element at the given index if it exists, fails otherwise. + * + * @param i The index at which to get the element to return. + * @return The element at the given index if it exists, fails otherwise. + */ + public final A index(final int i) { + if (i < 0) + throw error("index " + i + " out of range on stream"); + else { + Stream xs = this; + + for (int c = 0; c < i; c++) { + if (xs.isEmpty()) + throw error("index " + i + " out of range on stream"); + + xs = xs.tail()._1(); + } + + if (xs.isEmpty()) + throw error("index " + i + " out of range on stream"); + + return xs.head(); + } + } + + /** + * Returns true if the predicate holds for all of the elements of this stream, + * false otherwise (true for the empty stream). + * + * @param f the predicate function to test on each element of this stream. + * @return true if the predicate holds for all of the elements of this stream, + * false otherwise. + */ + public final boolean forall(final F f) { + return isEmpty() || f.f(head()) && tail()._1().forall(f); + } + + /** + * Returns true if the predicate holds for at least one of the elements of this + * stream, false otherwise (false for the empty stream). + * + * @param f The predicate function to test on the elements of this stream. + * @return true if the predicate holds for at least one of the elements of this + * stream. + */ + public final boolean exists(final F f) { + return dropWhile(not(f)).isNotEmpty(); + } + + /** + * Finds the first occurrence of an element that matches the given predicate or no value if no + * elements match. + * + * @param f The predicate function to test on elements of this stream. + * @return The first occurrence of an element that matches the given predicate or no value if no + * elements match. + */ + public final Option find(final F f) { + for (Stream as = this; as.isNotEmpty(); as = as.tail()._1()) { + if (f.f(as.head())) + return some(as.head()); + } + + return none(); + } + + /** + * Binds the given function across the stream of substreams of this stream. + * + * @param k A function to bind across this stream and its substreams. + * @return a new stream of the results of applying the given function to this stream and its substreams. + */ + public final Stream cobind(final F, B> k) { + return substreams().map(k); + } + + /** + * Returns a stream of the suffixes of this stream. A stream is considered to be a suffix of itself in this context. + * + * @return a stream of the suffixes of this stream, starting with the stream itself. + */ + public final Stream> tails() { + return isEmpty() ? Stream.>nil() : cons(this, new P1>>() { + public Stream> _1() { + return tail()._1().tails(); + } + }); + } + + /** + * Returns a stream of all prefixes of this stream. A stream is considered a prefix of itself in tnis context. + * + * @return a stream of the prefixes of this stream, starting with the stream itself. + */ + public final Stream> inits() { + final Stream> nil = Stream.cons(Stream.nil(), new P1>>() { + public Stream> _1() { + return nil(); + } + }); + return isEmpty() ? nil : nil.append(new P1>>() { + public Stream> _1() { + return tail()._1().inits().map(Stream.cons_().f(head())); + } + }); + } + + /** + * Returns a stream of all infixes of this stream. A stream is considered to contain itself. + * + * @return a stream of the infixes of this stream. + */ + public final Stream> substreams() { + return tails().bind(new F, Stream>>() { + public Stream> f(final Stream stream) { + return stream.inits(); + } + }); + } + + /** + * Returns the position of the first element matching the given predicate, if any. + * + * @param p A predicate to match. + * @return the position of the first element matching the given predicate, if any. + */ + public final Option indexOf(final F p) { + return zipIndex().find(new F, Boolean>() { + public Boolean f(final P2 p2) { + return p.f(p2._1()); + } + }).map(P2.__2()); + } + + /** + * Applies a stream of comonadic functions to this stream, returning a stream of values. + * + * @param fs A stream of comonadic functions to apply to this stream. + * @return A new stream of the results of applying the stream of functions to this stream. + */ + public final Stream sequenceW(final Stream, B>> fs) { + return fs.isEmpty() + ? Stream.nil() + : cons(fs.head().f(this), new P1>() { + public Stream _1() { + return sequenceW(fs.tail()._1()); + } + }); + } + + /** + * Converts this stream to a function of natural numbers. + * + * @return A function from natural numbers to values with the corresponding position in this stream. + */ + public final F toFunction() { + return new F() { + public A f(final Integer i) { + return index(i); + } + }; + } + + /** + * Converts a function of natural numbers to a stream. + * + * @param f The function to convert to a stream. + * @return A new stream of the results of the given function applied to the natural numbers, starting at 0. + */ + public static Stream fromFunction(final F f) { + return fromFunction(Enumerator.naturalEnumerator, f, Natural.ZERO); + } + + /** + * Converts a function of an enumerable type to a stream of the results of that function, + * starting at the given index. + * + * @param e An enumerator for the domain of the function. + * @param f The function to convert to a stream. + * @param i The index into the function at which to begin the stream. + * @return A new stream of the results of the given function applied to the values of the given enumerator, + * starting at the given value. + */ + public static Stream fromFunction(final Enumerator e, final F f, final B i) { + return cons(f.f(i), new P1>() { + public Stream _1() { + final Option s = e.successor(i); + return s.isSome() + ? fromFunction(e, f, s.some()) + : Stream.nil(); + } + }); + } + + /** + * Transforms a stream of pairs into a stream of first components and a stream of second components. + * + * @param xs The stream of pairs to transform. + * @return A stream of first components and a stream of second components. + */ + public static P2, Stream> unzip(final Stream> xs) { + return xs.foldRight(new F2, P1, Stream>>, P2, Stream>>() { + public P2, Stream> f(final P2 p, final P1, Stream>> ps) { + final P2, Stream> pp = ps._1(); + return P.p(cons(p._1(), P.p(pp._1())), cons(p._2(), P.p(pp._2()))); + } + }, P.p(Stream.nil(), Stream.nil())); + } + + /** + * A first-class version of the zipWith function. + * + * @return a function that zips two given streams with a given function. + */ + public static F, F, F>, Stream>>> zipWith() { + return curry(new F3, Stream, F>, Stream>() { + public Stream f(final Stream as, final Stream bs, final F> f) { + return as.zipWith(bs, f); + } + }); + } + + private static final class Nil extends Stream { + public A head() { + throw error("head on empty stream"); + } + + public P1> tail() { + throw error("tail on empty stream"); + } + } + + private static final class Cons extends Stream { + private final A head; + private final P1> tail; + + Cons(final A head, final P1> tail) { + this.head = head; + this.tail = tail.memo(); + } + + public A head() { + return head; + } + + public P1> tail() { + return tail; + } + + } + + /** + * Returns a function that prepends (cons) an element to a stream to produce a new stream. + * + * @return A function that prepends (cons) an element to a stream to produce a new stream. + */ + public static F>, Stream>> cons() { + return new F>, Stream>>() { + public F>, Stream> f(final A a) { + return new F>, Stream>() { + public Stream f(final P1> list) { + return cons(a, list); + } + }; + } + }; + } + + /** + * Returns a function that prepends (cons) an element to a stream to produce a new stream. + * + * @return A function that prepends (cons) an element to a stream to produce a new stream. + */ + public static F, Stream>> cons_() { + return curry(new F2, Stream>() { + public Stream f(final A a, final Stream as) { + return as.cons(a); + } + }); + } + + /** + * Returns an empty stream. + * + * @return An empty stream. + */ + public static Stream nil() { + return new Nil(); + } + + /** + * Returns an empty stream. + * + * @return An empty stream. + */ + public static P1> nil_() { + return new P1>() { + public Stream _1() { + return new Nil(); + } + }; + } + + /** + * Returns a function that determines whether a given stream is empty. + * + * @return A function that determines whether a given stream is empty. + */ + public static F, Boolean> isEmpty_() { + return new F, Boolean>() { + public Boolean f(final Stream as) { + return as.isEmpty(); + } + }; + } + + /** + * Returns a function that determines whether a given stream is not empty. + * + * @return A function that determines whether a given stream is not empty. + */ + public static F, Boolean> isNotEmpty_() { + return new F, Boolean>() { + public Boolean f(final Stream as) { + return as.isNotEmpty(); + } + }; + } + + /** + * Returns a stream of one element containing the given value. + * + * @param a The value for the head of the returned stream. + * @return A stream of one element containing the given value. + */ + public static Stream single(final A a) { + return cons(a, new P1>() { + public Stream _1() { + return nil(); + } + }); + } + + /** + * Returns a function that yields a stream containing its argument. + * + * @return a function that yields a stream containing its argument. + */ + public static F> single() { + return new F>() { + public Stream f(final A a) { + return single(a); + } + }; + } + + /** + * Prepends the given head element to the given tail element to produce a new stream. + * + * @param head The element to prepend. + * @param tail The stream to prepend to. + * @return The stream with the given element prepended. + */ + public static Stream cons(final A head, final P1> tail) { + return new Cons(head, tail); + } + + /** + * Joins the given stream of streams by concatenation. + * + * @param o The stream of streams to join. + * @return A new stream that is the join of the given streams. + */ + public static Stream join(final Stream> o) { + return Monoid.streamMonoid().sumRight(o); + } + + /** + * A first-class version of join + * + * @return A function that joins a stream of streams using a bind operation. + */ + public static F>, Stream> join() { + return new F>, Stream>() { + public Stream f(final Stream> as) { + return join(as); + } + }; + } + + /** + * Unfolds across the given function starting at the given value to produce a stream. + * + * @param f The function to unfold across. + * @param b The start value to begin the unfold. + * @return A new stream that is a result of unfolding until the function does not produce a + * value. + */ + public static Stream unfold(final F>> f, final B b) { + final Option> o = f.f(b); + if (o.isNone()) + return nil(); + else { + final P2 p = o.some(); + return cons(p._1(), new P1>() { + public Stream _1() { + return unfold(f, p._2()); + } + }); + } + } + + /** + * Creates a stream where the first item is calculated by applying the function on the third argument, + * the second item by applying the function on the previous result and so on. + * + * @param f The function to iterate with. + * @param p The predicate which must be true for the next item in order to continue the iteration. + * @param a The input to the first iteration. + * @return A stream where the first item is calculated by applying the function on the third argument, + * the second item by applying the function on the previous result and so on. + */ + public static Stream iterateWhile(final F f, final F p, final A a) { + return unfold( + new F>>() { + public Option> f(final A o) { + return Option.iif(new F, Boolean>() { + public Boolean f(final P2 p2) { + return p.f(o); + } + }, P.p(o, f.f(o))); + } + } + , a); + } + + /** + * Takes the given iterable to a stream. + * + * @param i The iterable to take to a stream. + * @return A stream from the given iterable. + */ + public static Stream iterableStream(final Iterable i) { + final class Util { + public Stream iteratorStream(final Iterator i) { + if (i.hasNext()) { + final A a = i.next(); + return cons(a, new P1>() { + public Stream _1() { + return iteratorStream(i); + } + }); + } else + return nil(); + } + } + + return new Util().iteratorStream(i.iterator()); + } + + /** + * Returns an infinite-length stream of the given element. + * + * @param a The element to repeat infinitely. + * @return An infinite-length stream of the given element. + */ + public static Stream repeat(final A a) { + return cons(a, new P1>() { + public Stream _1() { + return repeat(a); + } + }); + } + + /** + * Returns an infinite-length stream of the given elements cycling. Fails on the empty stream. + * + * @param as The elements to cycle infinitely. This must not be empty. + * @return An infinite-length stream of the given elements cycling. + */ + public static Stream cycle(final Stream as) { + if (as.isEmpty()) + throw error("cycle on empty list"); + else + return as.append(new P1>() { + public Stream _1() { + return cycle(as); + } + }); + } + + /** + * Returns a stream constructed by applying the given iteration function starting at the given value. + * + * @param f The iteration function. + * @param a The value to begin iterating from. + * @return A stream constructed by applying the given iteration function starting at the given value. + */ + public static Stream iterate(final F f, final A a) { + return cons(a, new P1>() { + public Stream _1() { + return iterate(f, f.f(a)); + } + }); + } + + /** + * A first-class version of the iterate function. + * + * @return A function that returns a stream constructed by applying a given iteration function + * starting at a given value. + */ + public static F, F>> iterate() { + return curry(new F2, A, Stream>() { + public Stream f(final F f, final A a) { + return iterate(f, a); + } + }); + } + + /** + * A first-class version of the bind function. + * + * @return A function that binds a given function across a given stream, joining the resulting streams. + */ + public static F>, F, Stream>> bind_() { + return curry(new F2>, Stream, Stream>() { + public Stream f(final F> f, final Stream as) { + return as.bind(f); + } + }); + } + + /** + * A first-class version of the foldRight function. + * + * @return A function that folds a given stream with a given function. + */ + public static F, B>>, F, B>>> foldRight() { + return curry(new F3, B>>, B, Stream, B>() { + public B f(final F, B>> f, final B b, final Stream as) { + return as.foldRight(f, b); + } + }); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Tree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Tree.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,379 @@ +package fj.data; + +import fj.F; +import fj.F2; +import fj.F2Functions; +import fj.P; +import fj.P1; +import fj.P2; +import static fj.Function.*; +import static fj.data.Stream.*; +import fj.Monoid; +import fj.Show; + +import java.util.Collection; +import java.util.Iterator; + +/** + * Provides a lazy, immutable, non-empty, multi-way tree (a rose tree). + * + * @version %build.number% + */ +public final class Tree implements Iterable { + /** + * Returns an iterator for this tree. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this tree. + */ + public Iterator iterator() { + return flatten().iterator(); + } + + private final A root; + private final P1>> subForest; + + private Tree(final A root, final P1>> subForest) { + this.root = root; + this.subForest = subForest; + } + + /** + * Creates a nullary tree. + * + * @param root The root element of the tree. + * @return A nullary tree with the root element in it. + */ + public static Tree leaf(final A root) { + return node(root, Stream.>nil()); + } + + /** + * Creates a new tree given a root and a (potentially infinite) subforest. + * + * @param root The root element of the tree. + * @param forest A stream of the tree's subtrees. + * @return A newly sprouted tree. + */ + public static Tree node(final A root, final P1>> forest) { + return new Tree(root, forest); + } + + /** + * Creates a new tree given a root and a (potentially infinite) subforest. + * + * @param root The root element of the tree. + * @param forest A stream of the tree's subtrees. + * @return A newly sprouted tree. + */ + public static Tree node(final A root, final Stream> forest) { + return new Tree(root, P.p(forest)); + } + + /** + * Creates a new n-ary given a root and a subforest of length n. + * + * @param root The root element of the tree. + * @param forest A list of the tree's subtrees. + * @return A newly sprouted tree. + */ + public static Tree node(final A root, final List> forest) { + return node(root, forest.toStream()); + } + + /** + * First-class constructor of trees. + * + * @return A function that constructs an n-ary tree given a root and a subforest or length n. + */ + public static F>>, Tree>> node() { + return curry(new F2>>, Tree>() { + public Tree f(final A a, final P1>> p1) { + return node(a, p1); + } + }); + } + + /** + * Returns the root element of the tree. + * + * @return The root element of the tree. + */ + public A root() { + return root; + } + + /** + * Returns a stream of the tree's subtrees. + * + * @return A stream of the tree's subtrees. + */ + public P1>> subForest() { + return subForest; + } + + /** + * Provides a transformation from a tree to its root. + * + * @return A transformation from a tree to its root. + */ + public static F, A> root_() { + return new F, A>() { + public A f(final Tree a) { + return a.root(); + } + }; + } + + /** + * Provides a transformation from a tree to its subforest. + * + * @return A transformation from a tree to its subforest. + */ + public static F, P1>>> subForest_() { + return new F, P1>>>() { + public P1>> f(final Tree a) { + return a.subForest(); + } + }; + } + + /** + * Puts the elements of the tree into a Stream, in pre-order. + * + * @return The elements of the tree in pre-order. + */ + public Stream flatten() { + final F2, P1>, Stream> squish = new F2, P1>, Stream>() { + public Stream f(final Tree t, final P1> xs) { + return cons(t.root(), t.subForest().map(Stream., Stream>foldRight().f(F2Functions.curry(this)).f(xs._1()))); + } + }; + return squish.f(this, P.p(Stream.nil())); + } + + /** + * flatten :: Tree a -> [a] + * flatten t = squish t [] + * where squish (Node x ts) xs = x:Prelude.foldr squish xs ts + * Puts the elements of the tree into a Stream, in pre-order. + * + * @return The elements of the tree in pre-order. + */ + public static F, Stream> flatten_() { + return new F, Stream>() { + public Stream f(final Tree t) { + return t.flatten(); + } + }; + } + + /** + * Provides a stream of the elements of the tree at each level, in level order. + * + * @return The elements of the tree at each level. + */ + public Stream> levels() { + final F>, Stream>> flatSubForests = + Stream., Tree>bind_().f(compose(P1.>>__1(), Tree.subForest_())); + final F>, Stream> roots = Stream., A>map_().f(Tree.root_()); + return iterateWhile(flatSubForests, Stream.>isNotEmpty_(), single(this)).map(roots); + } + + /** + * Maps the given function over this tree. + * + * @param f The function to map over this tree. + * @return The new Tree after the function has been applied to each element in this Tree. + */ + public Tree fmap(final F f) { + return node(f.f(root()), subForest().map(Stream., Tree>map_().f(Tree.fmap_().f(f)))); + } + + /** + * Provides a transformation to lift any function so that it maps over Trees. + * + * @return A transformation to lift any function so that it maps over Trees. + */ + public static F, F, Tree>> fmap_() { + return new F, F, Tree>>() { + public F, Tree> f(final F f) { + return new F, Tree>() { + public Tree f(final Tree a) { + return a.fmap(f); + } + }; + } + }; + } + + /** + * Folds this tree using the given monoid. + * + * @param f A transformation from this tree's elements, to the monoid. + * @param m The monoid to fold this tree with. + * @return The result of folding the tree with the given monoid. + */ + public B foldMap(final F f, final Monoid m) { + return m.sum(f.f(root()), m.sumRight(subForest()._1().map(foldMap_(f, m)).toList())); + } + + /** + * Projects an immutable collection of this tree. + * + * @return An immutable collection of this tree. + */ + public Collection toCollection() { + return flatten().toCollection(); + } + + /** + * Provides a function that folds a tree with the given monoid. + * + * @param f A transformation from a tree's elements to the monoid. + * @param m A monoid to fold the tree with. + * @return A function that, given a tree, folds it with the given monoid. + */ + public static F, B> foldMap_(final F f, final Monoid m) { + return new F, B>() { + public B f(final Tree t) { + return t.foldMap(f, m); + } + }; + } + + /** + * Builds a tree from a seed value. + * + * @param f A function with which to build the tree. + * @return A function which, given a seed value, yields a tree. + */ + public static F> unfoldTree(final F>>> f) { + return new F>() { + public Tree f(final B b) { + final P2>> p = f.f(b); + return node(p._1(), p._2().map(Stream.>map_().f(unfoldTree(f)))); + } + }; + } + + /** + * Applies the given function to all subtrees of this tree, returning a tree of the results (comonad pattern). + * + * @param f A function to bind across all the subtrees of this tree. + * @return A new tree, with the results of applying the given function to each subtree of this tree. The result + * of applying the function to the entire tree is the root label, and the results of applying to the + * root's children are labels of the root's subforest, etc. + */ + public Tree cobind(final F, B> f) { + return unfoldTree(new F, P2>>>>() { + public P2>>> f(final Tree t) { + return P.p(f.f(t), t.subForest()); + } + }).f(this); + } + + /** + * Expands this tree into a tree of trees, with this tree as the root label, and subtrees as the labels of + * child nodes (comonad pattern). + * + * @return A tree of trees, with this tree as its root label, and subtrees of this tree as the labels of + * its child nodes. + */ + public Tree> cojoin() { + final F, Tree> id = identity(); + return cobind(id); + } + + private static Stream drawSubTrees(final Show s, final Stream> ts) { + return ts.isEmpty() ? Stream.nil() + : ts.tail()._1().isEmpty() ? shift("`- ", " ", ts.head().drawTree(s)).cons("|") + : shift("+- ", "| ", ts.head().drawTree(s)) + .append(drawSubTrees(s, ts.tail()._1())); + } + + private static Stream shift(final String f, final String o, final Stream s) { + return Stream.repeat(o).cons(f).zipWith(s, Monoid.stringMonoid.sum()); + } + + private Stream drawTree(final Show s) { + return drawSubTrees(s, subForest._1()).cons(s.showS(root)); + } + + /** + * Draws a 2-dimensional representation of a tree. + * + * @param s A show instance for the elements of the tree. + * @return a String showing this tree in two dimensions. + */ + public String draw(final Show s) { + return Monoid.stringMonoid.join(drawTree(s), "\n"); + } + + /** + * Provides a show instance that draws a 2-dimensional representation of a tree. + * + * @param s A show instance for the elements of the tree. + * @return a show instance that draws a 2-dimensional representation of a tree. + */ + public static Show> show2D(final Show s) { + return Show.showS(new F, String>() { + public String f(final Tree tree) { + return tree.draw(s); + } + }); + } + + /** + * Zips this tree with another, using the given function. The resulting tree is the structural intersection + * of the two trees. + * + * @param bs A tree to zip this tree with. + * @param f A function with which to zip together the two trees. + * @return A new tree of the results of applying the given function over this tree and the given tree, position-wise. + */ + public Tree zipWith(final Tree bs, final F2 f) { + return F2Functions.zipTreeM(f).f(this, bs); + } + + /** + * Zips this tree with another, using the given function. The resulting tree is the structural intersection + * of the two trees. + * + * @param bs A tree to zip this tree with. + * @param f A function with which to zip together the two trees. + * @return A new tree of the results of applying the given function over this tree and the given tree, position-wise. + */ + public Tree zipWith(final Tree bs, final F> f) { + return zipWith(bs, uncurryF2(f)); + } + + /** + * Folds a Tree into a Tree by applying the function f from the bottom of the Tree to the top + * + * @param t A tree to fold from the bottom to the top. + * @param f A function transforming the current node and a stream of already transformed nodes (its children) into a new node + * @return The folded tree + */ + public static Tree bottomUp(Tree t, final F>, B> f) { + final F, Tree> recursiveCall = new F, Tree>() { + @Override public Tree f(Tree a) { + return bottomUp(a, f); + } + }; + + final Stream> tbs = t.subForest()._1().map(recursiveCall); + return Tree.node(f.f(P.p(t.root(), tbs.map(Tree. getRoot()))), tbs); + } + + /** + * @return a function getting the root of a Tree + */ + private static F, A> getRoot() { + return new F, A>() { + @Override public A f(Tree a) { + return a.root(); + } + }; + } + +} \ No newline at end of file diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/TreeMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/TreeMap.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,292 @@ +package fj.data; + +import fj.F; +import fj.F1Functions; +import fj.Ordering; +import fj.P; +import fj.P2; +import fj.P3; +import fj.Ord; + +import java.util.Iterator; +import java.util.Map; + +import static fj.Function.compose; +import static fj.Function.flip; +import static fj.P.p; +import static fj.data.IterableW.join; +import static fj.data.List.iterableList; + +/** + * An immutable, in-memory map, backed by a red-black tree. + */ +public final class TreeMap implements Iterable> { + private final Set>> tree; + + private TreeMap(final Set>> tree) { + this.tree = tree; + } + + private static Ord> ord(final Ord keyOrd) { + return keyOrd.comap(P2. __1()); + } + + /** + * Constructs an empty tree map. + * + * @param keyOrd + * An order for the keys of the tree map. + * @return an empty TreeMap with the given key order. + */ + public static TreeMap empty(final Ord keyOrd) { + return new TreeMap(Set.empty(TreeMap.> ord(keyOrd))); + } + + /** + * Returns a potential value that the given key maps to. + * + * @param k + * The key to look up in the tree map. + * @return A potential value for the given key. + */ + public Option get(final K k) { + Option op = Option. none(); + Option>> attribute = tree.mapGet(P.p(k, op)); + return attribute.bind(P2.> __2()); + // P3>>, Option>>, Set>>> splitTree = tree.split(P.p(k, op)); + // final Option>> x = splitTree._2(); + // + // System.out.println("aaaa"); + // return x.bind(P2.>__2()); + } + + public Option getLoop(final K k) { + Set>> cur = tree; + Option op = Option. none(); + + while (!cur.isEmpty()) { + P2> h = cur.head(); + Ordering i = cur.ord.compare(P.p(k,op),h); + if (i == Ordering.LT) + cur = cur.l(); + else if (i == Ordering.GT) + cur = cur.r(); + else + return h._2(); + + } + return Option.none(); + } + + /** + * Inserts the given key and value association into the tree map. If the given + * key is already mapped to a value, the old value is replaced with the given + * one. + * + * @param k + * The key to insert. + * @param v + * The value to insert. + * @return A new tree map with the given value mapped to the given key. + */ + public TreeMap set(final K k, final V v) { + return new TreeMap(tree.insert(P.p(k, Option.some(v)))); + } + + /** + * Deletes the entry in the tree map that corresponds to the given key. + * + * @param k + * The key to delete from this tree map. + * @return A new tree map with the entry corresponding to the given key + * removed. + */ + public TreeMap delete(final K k) { + return new TreeMap(tree.delete(P.p(k, Option. none()))); + } + + /** + * Returns the number of entries in this tree map. + * + * @return The number of entries in this tree map. + */ + public int size() { + return tree.size(); + } + + /** + * Determines if this tree map has any entries. + * + * @return true if this tree map has no entries, + * false otherwise. + */ + public boolean isEmpty() { + return tree.isEmpty(); + } + + /** + * Returns all values in this tree map. + * + * @return All values in this tree map. + */ + public List values() { + return iterableList(join(tree.toList().map(compose(IterableW.> wrap(), P2.> __2())))); + } + + /** + * Returns all keys in this tree map. + * + * @return All keys in this tree map. + */ + public List keys() { + return tree.toList().map(P2.> __1()); + } + + /** + * Determines if the given key value exists in this tree map. + * + * @param k + * The key value to look for in this tree map. + * @return true if this tree map contains the given key, + * false otherwise. + */ + public boolean contains(final K k) { + return tree.member(P.p(k, Option. none())); + } + + /** + * Returns an iterator for this map's key-value pairs. This method exists to + * permit the use in a for-each loop. + * + * @return A iterator for this map's key-value pairs. + */ + public Iterator> iterator() { + return join( + tree.toStream().map(P2., IterableW> map2_(IterableW.> wrap())) + .map(P2.tuple(compose(IterableW.> map(), P. p2())))).iterator(); + } + + /** + * A mutable map projection of this tree map. + * + * @return A new mutable map isomorphic to this tree map. + */ + public Map toMutableMap() { + final Map m = new java.util.TreeMap(); + for (final P2 e : this) { + m.put(e._1(), e._2()); + } + return m; + } + + /** + * An immutable projection of the given mutable map. + * + * @param ord + * An order for the map's keys. + * @param m + * A mutable map to project to an immutable one. + * @return A new immutable tree map isomorphic to the given mutable map. + */ + public static TreeMap fromMutableMap(final Ord ord, final Map m) { + TreeMap t = empty(ord); + for (final Map.Entry e : m.entrySet()) { + t = t.set(e.getKey(), e.getValue()); + } + return t; + } + + /** + * Returns a first-class version of the get method for this TreeMap. + * + * @return a functional representation of this TreeMap. + */ + public F> get() { + return new F>() { + public Option f(final K k) { + return get(k); + } + }; + } + + /** + * Modifies the value for the given key, if present, by applying the given + * function to it. + * + * @param k + * The key for the value to modify. + * @param f + * A function with which to modify the value. + * @return A new tree map with the value for the given key transformed by the + * given function, paired with True if the map was modified, otherwise + * False. + */ + public P2> update(final K k, final F f) { + final P2>>> up = tree.update(p(k, Option. none()), + P2., Option> map2_(Option. map().f(f))); + return P.p(up._1(), new TreeMap(up._2())); + } + + /** + * Modifies the value for the given key, if present, by applying the given + * function to it, or inserts the given value if the key is not present. + * + * @param k + * The key for the value to modify. + * @param f + * A function with which to modify the value. + * @param v + * A value to associate with the given key if the key is not already + * present. + * @return A new tree map with the value for the given key transformed by the + * given function. + */ + public TreeMap update(final K k, final F f, final V v) { + final P2> up = update(k, f); + return up._1() ? up._2() : set(k, v); + } + + /** + * Splits this TreeMap at the given key. Returns a triple of: + *
    + *
  • A set containing all the values of this map associated with keys less + * than the given key.
  • + *
  • An option of a value mapped to the given key, if it exists in this map, + * otherwise None. + *
  • A set containing all the values of this map associated with keys + * greater than the given key.
  • + *
+ * + * @param k + * A key at which to split this map. + * @return Two sets and an optional value, where all elements in the first set + * are mapped to keys less than the given key in this map, all the + * elements in the second set are mapped to keys greater than the + * given key, and the optional value is the value associated with the + * given key if present, otherwise None. + */ + public P3, Option, Set> split(final K k) { + final F>>, Set> getSome = F1Functions.mapSet( + F1Functions.o(Option. fromSome(), P2.> __2()), + tree.ord().comap(F1Functions.o(P.> p2().f(k), Option. some_()))); + return tree.split(p(k, Option. none())).map1(getSome).map3(getSome) + .map2(F1Functions.o(Option. join(), F1Functions.mapOption(P2.> __2()))); + } + + /** + * Maps the given function across the values of this TreeMap. + * + * @param f + * A function to apply to the values of this TreeMap. + * @return A new TreeMap with the values transformed by the given function. + */ + @SuppressWarnings({ "unchecked" }) + public TreeMap map(final F f) { + final F>, P2>> g = P2.map2_(F1Functions.mapOption(f)); + final F>> coord = flip(P.> p2()).f(Option. none()); + final Ord o = tree.ord().comap(coord); + return new TreeMap(tree.map(TreeMap.> ord(o), g)); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/TreeZipper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/TreeZipper.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,739 @@ +package fj.data; + +import fj.*; +import fj.function.Booleans; + +import java.util.Iterator; + +import static fj.Equal.p3Equal; +import static fj.Equal.p4Equal; +import static fj.Equal.streamEqual; +import static fj.Equal.treeEqual; +import static fj.Function.compose; +import static fj.Function.curry; +import static fj.Function.flip; +import static fj.Function.uncurryF2; +import static fj.Show.p3Show; +import static fj.Show.p4Show; +import static fj.Show.streamShow; +import static fj.Show.treeShow; +import static fj.data.Option.none; +import static fj.data.Option.some; +import static fj.data.Stream.nil; +import static fj.data.Stream.unfold; +import static fj.data.Tree.node; +import static fj.data.Tree.unfoldTree; + +/** + * Provides a zipper structure for rose trees, which is a Tree supplied with a location within that tree. + * Provides navigation, insertion, deletion, and memorization of visited locations within a tree. + */ +public final class TreeZipper
implements Iterable> { + + /** + * Returns an iterator of all the positions of this TreeZipper. Exists for use with the foreach syntax. + * + * @return An iterator of all the positions of this TreeZipper. + */ + public Iterator> iterator() { + return positions().toTree().iterator(); + } + + private final Tree tree; + private final Stream> lefts; + private final Stream> rights; + private final Stream>, A, Stream>>> parents; + + private TreeZipper(final Tree tree, + final Stream> lefts, + final Stream> rights, + final Stream>, A, Stream>>> parents) { + this.tree = tree; + this.lefts = lefts; + this.rights = rights; + this.parents = parents; + } + + /** + * Creates a new tree zipper given a currently selected tree, a forest on the left, a forest on the right, + * and a stream of parent contexts. + * + * @param tree The currently selected tree. + * @param lefts The selected tree's left siblings, closest first. + * @param rights The selected tree's right siblings, closest first. + * @param parents The parent of the selected tree, and the parent's siblings. + * @return A new zipper with the given tree selected, and the given forests on the left and right. + */ + public static TreeZipper treeZipper(final Tree tree, + final Stream> lefts, + final Stream> rights, + final Stream>, A, Stream>>> parents) { + return new TreeZipper(tree, lefts, rights, parents); + } + + /** + * First-class constructor for tree zippers. + * + * @return A function that returns a new tree zipper, given a selected tree, left and right siblings, + * and a parent context. + */ + public static + F, F>, F>, F>, A, Stream>>>, TreeZipper>>>> + treeZipper() { + return curry( + new F4, Stream>, Stream>, Stream>, A, Stream>>>, TreeZipper>() { + public TreeZipper f(final Tree tree, + final Stream> lefts, + final Stream> rights, + final Stream>, A, Stream>>> parents) { + return treeZipper(tree, lefts, rights, parents); + } + }); + } + + /** + * Returns the product-4 representation of this zipper. + * + * @return the product-4 representation of this zipper. + */ + public P4, Stream>, Stream>, Stream>, A, Stream>>>> p() { + return P.p(tree, lefts, rights, parents); + } + + /** + * A first-class function that returns the product-4 representation of a given zipper. + * + * @return a function that converts a given zipper to its product-4 representation. + */ + public static + F, P4, Stream>, Stream>, Stream>, A, Stream>>>>> p_() { + return new F< + TreeZipper, + P4, + Stream>, + Stream>, + Stream>, A, Stream>>>>>() { + public P4< + Tree, + Stream>, + Stream>, + Stream>, A, Stream>>>> f(final TreeZipper a) { + return a.p(); + } + }; + } + + /** + * An Equal instance for tree zippers. + * + * @param e An Equal instance for tree elements. + * @return An Equal instance for tree zippers. + */ + public static Equal> eq(final Equal e) { + return p4Equal( + treeEqual(e), + streamEqual(treeEqual(e)), + streamEqual(treeEqual(e)), + streamEqual(p3Equal(streamEqual(treeEqual(e)), e, streamEqual(treeEqual(e))))).comap(TreeZipper.p_()); + } + + /** + * A Show instance for tree zippers. + * + * @param s A Show instance for tree elements. + * @return A Show instance for tree zippers. + */ + public static Show> show(final Show s) { + return p4Show( + treeShow(s), + streamShow(treeShow(s)), + streamShow(treeShow(s)), + streamShow(p3Show(streamShow(treeShow(s)), s, streamShow(treeShow(s))))).comap(TreeZipper.p_()); + } + + private static Stream> combChildren(final Stream> ls, + final Tree t, + final Stream> rs) { + return ls.foldLeft(compose(flip(Stream.>cons()), P.>>p1()), Stream.cons(t, P.p(rs))); + } + + /** + * Navigates to the parent of the current location. + * + * @return A new tree zipper focused on the parent node of the current node, + * or none if the current node is the root node. + */ + public Option> parent() { + if (parents.isEmpty()) + return none(); + else { + final P3>, A, Stream>> p = parents.head(); + return some(treeZipper(node(p._2(), combChildren(lefts, tree, rights)), p._1(), p._3(), parents.tail()._1())); + } + } + + /** + * Navigates to the top-most parent of the current location. + * + * @return A new tree zipper focused on the top-most parent of the current node. + */ + public TreeZipper root() { + return parent().option(this, TreeZipper.root_()); + } + + /** + * A first-class version of the root function. + * + * @return A function that returns a new tree-zipper focused on the root of the given tree zipper's tree. + */ + public static F, TreeZipper> root_() { + return new F, TreeZipper>() { + public TreeZipper f(final TreeZipper a) { + return a.root(); + } + }; + } + + /** + * Navigates to the left sibling of the current location. + * + * @return A new tree zipper focused on the left sibling of the current node, + * or none if there are no siblings on the left. + */ + public Option> left() { + return lefts.isEmpty() ? Option.>none() + : some(treeZipper(lefts.head(), lefts.tail()._1(), rights.cons(tree), parents)); + } + + /** + * Navigates to the right sibling of the current location. + * + * @return A new tree zipper focused on the right sibling of the current node, + * or none if there are no siblings on the right. + */ + public Option> right() { + return rights.isEmpty() ? Option.>none() + : some(treeZipper(rights.head(), lefts.cons(tree), rights.tail()._1(), parents)); + } + + /** + * Navigtes to the first child of the current location. + * + * @return A new tree zipper focused on the first child of the current node, or none if the node has no children. + */ + public Option> firstChild() { + final Stream> ts = tree.subForest()._1(); + return ts.isEmpty() ? Option.>none() + : some(treeZipper(ts.head(), Stream.>nil(), ts.tail()._1(), downParents())); + } + + /** + * Navigtes to the last child of the current location. + * + * @return A new tree zipper focused on the last child of the current node, or none if the node has no children. + */ + public Option> lastChild() { + final Stream> ts = tree.subForest()._1().reverse(); + return ts.isEmpty() ? Option.>none() + : some(treeZipper(ts.head(), ts.tail()._1(), Stream.>nil(), downParents())); + } + + /** + * Navigates to the given child of the current location, starting at index 0. + * + * @param n The index of the child to which to navigate. + * @return An optional tree zipper focused on the child node at the given index, or none if there is no such child. + */ + public Option> getChild(final int n) { + Option> r = none(); + for (final P2>, Stream>> lr + : splitChildren(Stream.>nil(), tree.subForest()._1(), n)) { + r = some(treeZipper(lr._1().head(), lr._1().tail()._1(), lr._2(), downParents())); + } + return r; + } + + /** + * Navigates to the first child of the current location, that satisfies the given predicate. + * + * @param p A predicate to be satisfied by the child node. + * @return An optional tree zipper focused on the first child node that satisfies the given predicate, + * or none if there is no such child. + */ + public Option> findChild(final F, Boolean> p) { + Option> r = none(); + + final F2>, Stream>, Option>, Tree, Stream>>>> split = + new F2>, Stream>, Option>, Tree, Stream>>>>() { + public Option>, Tree, Stream>>> f(final Stream> acc, + final Stream> xs) { + return xs.isNotEmpty() + ? p.f(xs.head()) ? some(P.p(acc, xs.head(), xs.tail()._1())) + : f(acc.cons(xs.head()), xs.tail()._1()) + : Option.>, Tree, Stream>>>none(); + } + }; + + Stream> subforest = tree.subForest()._1(); + if (subforest.isNotEmpty()) { + for (final P3>, Tree, Stream>> ltr + : split.f(Stream.>nil(), subforest)) { + r = some(treeZipper(ltr._2(), ltr._1(), ltr._3(), downParents())); + } + } + return r; + } + + private Stream>, A, Stream>>> downParents() { + return parents.cons(P.p(lefts, tree.root(), rights)); + } + + private static Option, Stream>> splitChildren(final Stream acc, + final Stream xs, + final int n) { + return n == 0 ? some(P.p(acc, xs)) + : xs.isNotEmpty() ? splitChildren(acc.cons(xs.head()), xs.tail()._1(), n - 1) + : Option., Stream>>none(); + } + + private static Stream>, A, Stream>>> lp3nil() { + return nil(); + } + + /** + * Creates a new tree zipper focused on the root of the given tree. + * + * @param t A tree over which to create a new zipper. + * @return a new tree zipper focused on the root of the given tree. + */ + public static TreeZipper fromTree(final Tree t) { + return treeZipper(t, Stream.>nil(), Stream.>nil(), TreeZipper.lp3nil()); + } + + /** + * Creates a new tree zipper focused on the first element of the given forest. + * + * @param ts A forest over which to create a new zipper. + * @return a new tree zipper focused on the first element of the given forest. + */ + public static Option> fromForest(final Stream> ts) { + return ts.isNotEmpty() + ? some(treeZipper(ts.head(), Stream.>nil(), ts.tail()._1(), TreeZipper.lp3nil())) + : Option.>none(); + } + + /** + * Returns the tree containing this location. + * + * @return the tree containing this location. + */ + public Tree toTree() { + return root().tree; + } + + /** + * Returns the forest containing this location. + * + * @return the forest containing this location. + */ + public Stream> toForest() { + final TreeZipper r = root(); + return combChildren(r.lefts, r.tree, r.rights); + } + + /** + * Returns the tree at the currently focused node. + * + * @return the tree at the currently focused node. + */ + public Tree focus() { + return tree; + } + + /** + * Returns the left siblings of the currently focused node. + * + * @return the left siblings of the currently focused node. + */ + public Stream> lefts() { + return lefts; + } + + /** + * Returns the right siblings of the currently focused node. + * + * @return the right siblings of the currently focused node. + */ + public Stream> rights() { + return rights; + } + + /** + * Indicates whether the current node is at the top of the tree. + * + * @return true if the current node is the root of the tree, otherwise false. + */ + public boolean isRoot() { + return parents.isEmpty(); + } + + /** + * Indicates whether the current node is the leftmost tree in the current forest. + * + * @return true if the current node has no left siblings, otherwise false. + */ + public boolean isFirst() { + return lefts.isEmpty(); + } + + /** + * Indicates whether the current node is the rightmost tree in the current forest. + * + * @return true if the current node has no siblings on its right, otherwise false. + */ + public boolean isLast() { + return rights.isEmpty(); + } + + /** + * Indicates whether the current node is at the bottom of the tree. + * + * @return true if the current node has no child nodes, otherwise false. + */ + public boolean isLeaf() { + return tree.subForest()._1().isEmpty(); + } + + /** + * Indicates whether the current node is a child node of another node. + * + * @return true if the current node has a parent node, otherwise false. + */ + public boolean isChild() { + return !isRoot(); + } + + /** + * Indicates whether the current node has any child nodes. + * + * @return true if the current node has child nodes, otherwise false. + */ + public boolean hasChildren() { + return !isLeaf(); + } + + /** + * Replaces the current node with the given tree. + * + * @param t A tree with which to replace the current node. + * @return A new tree zipper in which the focused node is replaced with the given tree. + */ + public TreeZipper setTree(final Tree t) { + return treeZipper(t, lefts, rights, parents); + } + + /** + * Modifies the current node with the given function. + * + * @param f A function with which to modify the current tree. + * @return A new tree zipper in which the focused node has been transformed by the given function. + */ + public TreeZipper modifyTree(final F, Tree> f) { + return setTree(f.f(tree)); + } + + /** + * Modifies the label at the current node with the given function. + * + * @param f A function with which to transform the current node's label. + * @return A new tree zipper with the focused node's label transformed by the given function. + */ + public TreeZipper modifyLabel(final F f) { + return setLabel(f.f(getLabel())); + } + + /** + * Replaces the label of the current node with the given value. + * + * @param v The new value for the node's label. + * @return A new tree zipper with the focused node's label replaced by the given value. + */ + public TreeZipper setLabel(final A v) { + return modifyTree(new F, Tree>() { + public Tree f(final Tree t) { + return Tree.node(v, t.subForest()); + } + }); + } + + /** + * Returns the label at the current node. + * + * @return the label at the current node. + */ + public A getLabel() { + return tree.root(); + } + + /** + * Inserts a tree to the left of the current position. The inserted tree becomes the current tree. + * + * @param t A tree to insert to the left of the current position. + * @return A new tree zipper with the given tree in focus and the current tree on the right. + */ + public TreeZipper insertLeft(final Tree t) { + return treeZipper(t, lefts, rights.cons(tree), parents); + } + + /** + * Inserts a tree to the right of the current position. The inserted tree becomes the current tree. + * + * @param t A tree to insert to the right of the current position. + * @return A new tree zipper with the given tree in focus and the current tree on the left. + */ + public TreeZipper insertRight(final Tree t) { + return treeZipper(t, lefts.cons(tree), rights, parents); + } + + /** + * Inserts a tree as the first child of the current node. The inserted tree becomes the current tree. + * + * @param t A tree to insert. + * @return A new tree zipper with the given tree in focus, as the first child of the current node. + */ + public TreeZipper insertDownFirst(final Tree t) { + return treeZipper(t, Stream.>nil(), tree.subForest()._1(), downParents()); + } + + /** + * Inserts a tree as the last child of the current node. The inserted tree becomes the current tree. + * + * @param t A tree to insert. + * @return A new tree zipper with the given tree in focus, as the last child of the current node. + */ + public TreeZipper insertDownLast(final Tree t) { + return treeZipper(t, tree.subForest()._1().reverse(), Stream.>nil(), downParents()); + } + + /** + * Inserts a tree at the specified location in the current node's stream of children. The inserted tree + * becomes the current node. + * + * @param n The index at which to insert the given tree, starting at 0. + * @param t A tree to insert. + * @return A new tree zipper with the given tree in focus, at the specified index in the current node's stream + * of children, or None if the current node has fewer than n children. + */ + public Option> insertDownAt(final int n, final Tree t) { + Option> r = none(); + for (final P2>, Stream>> lr + : splitChildren(Stream.>nil(), tree.subForest()._1(), n)) { + r = some(treeZipper(t, lr._1(), lr._2(), downParents())); + } + return r; + } + + /** + * Removes the current node from the tree. The new position becomes the right sibling, or the left sibling + * if the current node has no right siblings, or the parent node if the current node has no siblings. + * + * @return A new tree zipper with the current node removed. + */ + public Option> delete() { + Option> r = none(); + if (rights.isNotEmpty()) + r = some(treeZipper(rights.head(), lefts, rights.tail()._1(), parents)); + else if (lefts.isNotEmpty()) + r = some(treeZipper(lefts.head(), lefts.tail()._1(), rights, parents)); + else for (final TreeZipper loc : parent()) + r = some(loc.modifyTree(new F, Tree>() { + public Tree f(final Tree t) { + return node(t.root(), Stream.>nil()); + } + })); + return r; + } + + /** + * Zips the nodes in this zipper with a boolean that indicates whether that node has focus. + * All of the booleans will be false, except for the focused node. + * + * @return A new zipper of pairs, with each node of this zipper paired with a boolean that is true if that + * node has focus, and false otherwise. + */ + public TreeZipper> zipWithFocus() { + final F> f = flip(P.p2()).f(false); + return map(f).modifyLabel(P2.map2_(Booleans.not)); + } + + /** + * Maps the given function across this zipper (covariant functor pattern). + * + * @param f A function to map across this zipper. + * @return A new zipper with the given function applied to the label of every node. + */ + public TreeZipper map(final F f) { + final F, Tree> g = Tree.fmap_().f(f); + final F>, Stream>> h = Stream., Tree>map_().f(g); + return treeZipper(tree.fmap(f), lefts.map(g), rights.map(g), parents.map( + new F>, A, Stream>>, P3>, B, Stream>>>() { + public P3>, B, Stream>> f(final P3>, A, Stream>> p) { + return p.map1(h).map2(f).map3(h); + } + })); + } + + /** + * First-class conversion of a Tree to the corresponding tree zipper. + * + * @return A function that takes a tree to its tree zipper representation. + */ + public static F, TreeZipper> fromTree() { + return new F, TreeZipper>() { + public TreeZipper f(final Tree t) { + return fromTree(t); + } + }; + } + + /** + * A first-class version of the left() function. + * + * @return A function that focuses the given tree zipper on its left sibling. + */ + public static F, Option>> left_() { + return new F, Option>>() { + public Option> f(final TreeZipper z) { + return z.left(); + } + }; + } + + /** + * A first-class version of the right() function. + * + * @return A function that focuses the given tree zipper on its right sibling. + */ + public static F, Option>> right_() { + return new F, Option>>() { + public Option> f(final TreeZipper z) { + return z.right(); + } + }; + } + + /** + * Returns a zipper over the tree of all possible permutations of this tree zipper (comonad pattern). + * This tree zipper becomes the focused node of the new zipper. + * + * @return A tree zipper over the tree of all possible permutations of this tree zipper. + */ + public TreeZipper> positions() { + final Tree> t = unfoldTree(TreeZipper.dwn()).f(this); + final Stream>> l = uf(TreeZipper.left_()); + final Stream>> r = uf(TreeZipper.right_()); + final Stream>>, TreeZipper, Stream>>>> p = unfold( + new F>, + Option>>, TreeZipper, Stream>>>, + Option>>>>() { + public Option>>, TreeZipper, Stream>>>, + Option>>> f(final Option> o) { + Option>>, TreeZipper, Stream>>>, + Option>>> r = none(); + for (final TreeZipper z : o) { + r = some(P.p(P.p(z.uf(TreeZipper.left_()), z, z.uf(TreeZipper.right_())), z.parent())); + } + return r; + } + }, parent()); + return treeZipper(t, l, r, p); + } + + private Stream>> uf(final F, Option>> f) { + return unfold( + new F>, Option>, Option>>>>() { + public Option>, Option>>> f(final Option> o) { + Option>, Option>>> r = none(); + for (final TreeZipper c : o) { + r = some(P.p(unfoldTree(TreeZipper.dwn()).f(c), f.f(c))); + } + return r; + } + }, f.f(this)); + } + + private static F, P2, P1>>>> dwn() { + return new F, P2, P1>>>>() { + public P2, P1>>> f(final TreeZipper tz) { + return P., P1>>>p(tz, new P1>>() { + private F>, Option, Option>>>> fwd() { + return new F>, Option, Option>>>>() { + public Option, Option>>> f(final Option> o) { + Option, Option>>> r = none(); + for (final TreeZipper c : o) { + r = some(P.p(c, c.right())); + } + return r; + } + }; + } + + public Stream> _1() { + return unfold(fwd(), tz.firstChild()); + } + }); + } + }; + } + + /** + * Maps the given function over the tree of all positions for this zipper (comonad pattern). Returns a zipper + * over the tree of results of the function application. + * + * @param f A function to map over the tree of all positions for this zipper. + * @return A zipper over the tree of results of the function application. + */ + public TreeZipper cobind(final F, B> f) { + return positions().map(f); + } + + /** + * A first-class version of the findChild function. + * + * @return a function that finds the first child, of a given tree zipper, that matches a given predicate. + */ + public static F2, Boolean>, TreeZipper, Option>> findChild() { + return new F2, Boolean>, TreeZipper, Option>>() { + public Option> f(final F, Boolean> f, final TreeZipper az) { + return az.findChild(f); + } + }; + } + + /** + * Zips this TreeZipper with another, applying the given function lock-step over both zippers in all directions. + * The structure of the resulting TreeZipper is the structural intersection of the two TreeZippers. + * + * @param bs A TreeZipper to zip this one with. + * @param f A function with which to zip together the two TreeZippers. + * @return The result of applying the given function over this TreeZipper and the given TreeZipper, location-wise. + */ + public TreeZipper zipWith(final TreeZipper bs, final F2 f) { + return F2Functions.zipTreeZipperM(f).f(this, bs); + } + + /** + * Zips this TreeZipper with another, applying the given function lock-step over both zippers in all directions. + * The structure of the resulting TreeZipper is the structural intersection of the two TreeZippers. + * + * @param bs A TreeZipper to zip this one with. + * @param f A function with which to zip together the two TreeZippers. + * @return The result of applying the given function over this TreeZipper and the given TreeZipper, location-wise. + */ + public TreeZipper zipWith(final TreeZipper bs, final F> f) { + return zipWith(bs, uncurryF2(f)); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Validation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Validation.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,1305 @@ +package fj.data; + +import fj.*; +import fj.function.Effect1; + +import static fj.Function.curry; +import static fj.P.p; + +import static fj.Unit.unit; +import static fj.Bottom.error; + +import java.util.Iterator; + +/** + * Isomorphic to {@link Either} but has renamed functions and represents failure on the left and success on the right. + * This type also has accumulating functions that accept a {@link Semigroup} for binding computation while keeping error + * values + * + * @version %build.number% + */ +public class Validation implements Iterable { + private final Either e; + + protected Validation(final Either e) { + this.e = e; + } + + /** + * Returns true if this is a failure, false otherwise. + * + * @return true if this is a failure, false otherwise. + */ + public boolean isFail() { + return e.isLeft(); + } + + /** + * Returns true if this is a success, false otherwise. + * + * @return true if this is a success, false otherwise. + */ + public boolean isSuccess() { + return e.isRight(); + } + + /** + * Returns the failing value, or throws an error if there is no failing value. + * + * @return the failing value, or throws an error if there is no failing value. + */ + public E fail() { + if (isFail()) + return e.left().value(); + else + throw error("Validation: fail on success value"); + } + + /** + * Returns the success value, or throws an error if there is no success value. + * + * @return the success value, or throws an error if there is no success value. + */ + public T success() { + if (isSuccess()) + return e.right().value(); + else + throw error("Validation: success on fail value"); + } + + /** + * The catamorphism for validation. Folds over this validation breaking into left or right. + * + * @param fail The function to call if this failed. + * @param success The function to call if this succeeded. + * @return The reduced value. + */ + public X validation(final F fail, final F success) { + return e.either(fail, success); + } + + /** + * Returns a failing projection of this validation. + * + * @return a failing projection of this validation. + */ + public FailProjection f() { + return new FailProjection(this); + } + + /** + * Returns an either projection of this validation. + * + * @return An either projection of this validation. + */ + public Either toEither() { + return e; + } + + /** + * Returns the success value or fails with the given error message. + * + * @param err The error message to fail with. + * @return The success value. + */ + public T successE(final P1 err) { + return e.right().valueE(err); + } + + /** + * Returns the success value or fails with the given error message. + * + * @param err The error message to fail with. + * @return The success value. + */ + public T successE(final String err) { + return e.right().valueE(p(err)); + } + + /** + * Returns the success value or the given value. + * + * @param t The value to return if this is failure. + * @return The success value or the given value. + */ + public T orSuccess(final P1 t) { + return e.right().orValue(t); + } + + /** + * Returns the success value or the given value. + * + * @param t The value to return if this is failure. + * @return The success value or the given value. + */ + public T orSuccess(final T t) { + return e.right().orValue(p(t)); + } + + /** + * The success value or the application of the given function to the failing value. + * + * @param f The function to execute on the failing value. + * @return The success value or the application of the given function to the failing value. + */ + public T on(final F f) { + return e.right().on(f); + } + + /** + * Executes a side-effect on the success value if there is one. + * + * @param f The side-effect to execute. + * @return The unit value. + */ + public Unit foreach(final F f) { + return e.right().foreach(f); + } + + /** + * Executes a side-effect on the success value if there is one. + * + * @param f The side-effect to execute. + */ + public void foreachDoEffect(final Effect1 f) { + e.right().foreachDoEffect(f); + } + + /** + * Maps the given function across the success side of this validation. + * + * @param f The function to map. + * @return A new validation with the function mapped. + */ + @SuppressWarnings({"unchecked"}) + public Validation map(final F f) { + return isFail() ? + Validation.fail(fail()) : + Validation.success(f.f(success())); + } + + /** + * Binds the given function across this validation's success value if it has one. + * + * @param f The function to bind across this validation. + * @return A new validation value after binding. + */ + @SuppressWarnings({"unchecked"}) + public Validation bind(final F> f) { + return isSuccess() ? f.f(success()) : Validation.fail(fail()); + } + + /** + * Anonymous bind through this validation. + * + * @param v The value to bind with. + * @return A validation after binding. + */ + public Validation sequence(final Validation v) { + return bind(Function.>constant(v)); + } + + /** + * Returns None if this is a failure or if the given predicate p does not hold for the + * success value, otherwise, returns a success in Some. + * + * @param f The predicate function to test on this success value. + * @return None if this is a failure or if the given predicate p does not hold for the + * success value, otherwise, returns a success in Some. + */ + public Option> filter(final F f) { + return e.right().filter(f).map(Validation.validation()); + } + + /** + * Function application on the success value. + * + * @param v The validation of the function to apply on the success value. + * @return The result of function application in validation. + */ + public Validation apply(final Validation> v) { + return v.bind(new F, Validation>() { + public Validation f(final F f) { + return map(f); + } + }); + } + + /** + * Returns true if this is a failure or returns the result of the application of the given + * function to the success value. + * + * @param f The predicate function to test on this success value. + * @return true if this is a failure or returns the result of the application of the given + * function to the success value. + */ + public boolean forall(final F f) { + return e.right().forall(f); + } + + /** + * Returns false if this is a failure or returns the result of the application of the given + * function to the success value. + * + * @param f The predicate function to test on this success value. + * @return false if this is a failure or returns the result of the application of the given + * function to the success value. + */ + public boolean exists(final F f) { + return e.right().exists(f); + } + + /** + * Returns a single element list if this is a success value, otherwise an empty list. + * + * @return A single element list if this is a success value, otherwise an empty list. + */ + public List toList() { + return e.right().toList(); + } + + /** + * Returns the success value in Some if there is one, otherwise None. + * + * @return The success value in Some if there is one, otherwise None. + */ + public Option toOption() { + return e.right().toOption(); + } + + /** + * Returns a single element array if this is a success value, otherwise an empty list. + * + * @return A single element array if this is a success value, otherwise an empty list. + */ + public Array toArray() { + return e.right().toArray(); + } + + /** + * Returns a single element stream if this is a success value, otherwise an empty list. + * + * @return A single element stream if this is a success value, otherwise an empty list. + */ + public Stream toStream() { + return e.right().toStream(); + } + + /** + * Function application on the successful side of this validation, or accumulating the errors on the failing side + * using the given semigroup should one or more be encountered. + * + * @param s The semigroup to accumulate errors with if + * @param v The validating function to apply. + * @return A failing validation if this or the given validation failed (with errors accumulated if both) or a + * succeeding validation if both succeeded. + */ + @SuppressWarnings({"unchecked"}) + public Validation accumapply(final Semigroup s, final Validation> v) { + return isFail() ? + Validation.fail(v.isFail() ? + s.sum(v.fail(), fail()) : + fail()) : + v.isFail() ? + Validation.fail(v.fail()) : + Validation.success(v.success().f(success())); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, final F> f) { + return va.accumapply(s, map(f)); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, final F2 f) { + return va.accumapply(s, map(curry(f))); + } + + /** + * Accumulates errors anonymously. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @return A Some if one or more validations failed (accumulated with the semigroup), otherwise, + * None. + */ + public Option accumulate(final Semigroup s, final Validation va) { + return accumulate(s, va, new F2() { + public Unit f(final T t, final A a) { + return unit(); + } + }).f().toOption(); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, + final Validation vb, final F>> f) { + return vb.accumapply(s, accumulate(s, va, f)); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, + final Validation vb, final F3 f) { + return vb.accumapply(s, accumulate(s, va, curry(f))); + } + + /** + * Accumulates errors anonymously. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @return A Some if one or more validations failed (accumulated with the semigroup), otherwise, + * None. + */ + public Option accumulate(final Semigroup s, final Validation va, final Validation vb) { + return accumulate(s, va, vb, new F3() { + public Unit f(final T t, final A a, final B b) { + return unit(); + } + }).f().toOption(); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, + final Validation vb, final Validation vc, + final F>>> f) { + return vc.accumapply(s, accumulate(s, va, vb, f)); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, + final Validation vb, final Validation vc, + final F4 f) { + return vc.accumapply(s, accumulate(s, va, vb, curry(f))); + } + + /** + * Accumulates errors anonymously. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @return A Some if one or more validations failed (accumulated with the semigroup), otherwise, + * None. + */ + public Option accumulate(final Semigroup s, final Validation va, final Validation vb, + final Validation vc) { + return accumulate(s, va, vb, vc, new F4() { + public Unit f(final T t, final A a, final B b, final C c) { + return unit(); + } + }).f().toOption(); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param vd The fifth validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, + final Validation vb, final Validation vc, + final Validation vd, + final F>>>> f) { + return vd.accumapply(s, accumulate(s, va, vb, vc, f)); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param vd The fifth validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, + final Validation vb, final Validation vc, + final Validation vd, final F5 f) { + return vd.accumapply(s, accumulate(s, va, vb, vc, curry(f))); + } + + /** + * Accumulates errors anonymously. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param vd The fifth validation to accumulate errors with if it failed. + * @return A Some if one or more validations failed (accumulated with the semigroup), otherwise, + * None. + */ + public Option accumulate(final Semigroup s, final Validation va, final Validation vb, + final Validation vc, final Validation vd) { + return accumulate(s, va, vb, vc, vd, new F5() { + public Unit f(final T t, final A a, final B b, final C c, final D d) { + return unit(); + } + }).f().toOption(); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param vd The fifth validation to accumulate errors with if it failed. + * @param ve The sixth validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, + final Validation vb, final Validation vc, + final Validation vd, final Validation ve, + final F>>>>> f) { + return ve.accumapply(s, accumulate(s, va, vb, vc, vd, f)); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param vd The fifth validation to accumulate errors with if it failed. + * @param ve The sixth validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, + final Validation vb, final Validation vc, + final Validation vd, final Validation ve, + final F6 f) { + return ve.accumapply(s, accumulate(s, va, vb, vc, vd, curry(f))); + } + + /** + * Accumulates errors anonymously. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param vd The fifth validation to accumulate errors with if it failed. + * @param ve The sixth validation to accumulate errors with if it failed. + * @return A Some if one or more validations failed (accumulated with the semigroup), otherwise, + * None. + */ + public Option accumulate(final Semigroup s, final Validation va, + final Validation vb, final Validation vc, + final Validation vd, final Validation ve) { + return accumulate(s, va, vb, vc, vd, ve, new F6() { + public Unit f(final T t, final A a, final B b, final C c, final D d, final E$ e) { + return unit(); + } + }).f().toOption(); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param vd The fifth validation to accumulate errors with if it failed. + * @param ve The sixth validation to accumulate errors with if it failed. + * @param vf The seventh validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, + final Validation vb, final Validation vc, + final Validation vd, final Validation ve, + final Validation vf, + final F>>>>>> f) { + return vf.accumapply(s, accumulate(s, va, vb, vc, vd, ve, f)); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param vd The fifth validation to accumulate errors with if it failed. + * @param ve The sixth validation to accumulate errors with if it failed. + * @param vf The seventh validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, + final Validation vb, final Validation vc, + final Validation vd, final Validation ve, + final Validation vf, + final F7 f) { + return vf.accumapply(s, accumulate(s, va, vb, vc, vd, ve, curry(f))); + } + + /** + * Accumulates errors anonymously. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param vd The fifth validation to accumulate errors with if it failed. + * @param ve The sixth validation to accumulate errors with if it failed. + * @param vf The seventh validation to accumulate errors with if it failed. + * @return A Some if one or more validations failed (accumulated with the semigroup), otherwise, + * None. + */ + public Option accumulate(final Semigroup s, final Validation va, + final Validation vb, final Validation vc, + final Validation vd, final Validation ve, + final Validation vf) { + return accumulate(s, va, vb, vc, vd, ve, vf, new F7() { + public Unit f(final T t, final A a, final B b, final C c, final D d, final E$ e, final F$ f) { + return unit(); + } + }).f().toOption(); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param vd The fifth validation to accumulate errors with if it failed. + * @param ve The sixth validation to accumulate errors with if it failed. + * @param vf The seventh validation to accumulate errors with if it failed. + * @param vg The eighth validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, + final Validation vb, final Validation vc, + final Validation vd, final Validation ve, + final Validation vf, final Validation vg, + final F>>>>>>> f) { + return vg.accumapply(s, accumulate(s, va, vb, vc, vd, ve, vf, f)); + } + + /** + * Accumulates errors on the failing side of this or any given validation if one or more are encountered, or applies + * the given function if all succeeded and returns that value on the successful side. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param vd The fifth validation to accumulate errors with if it failed. + * @param ve The sixth validation to accumulate errors with if it failed. + * @param vf The seventh validation to accumulate errors with if it failed. + * @param vg The eighth validation to accumulate errors with if it failed. + * @param f The function to apply if all validations have succeeded. + * @return A succeeding validation if all validations succeeded, or a failing validation with errors accumulated if + * one or more failed. + */ + public Validation accumulate(final Semigroup s, final Validation va, + final Validation vb, final Validation vc, + final Validation vd, final Validation ve, + final Validation vf, final Validation vg, + final F8 f) { + return vg.accumapply(s, accumulate(s, va, vb, vc, vd, ve, vf, curry(f))); + } + + /** + * Accumulates errors anonymously. + * + * @param s The semigroup to accumulate errors with if one or more validations fail. + * @param va The second validation to accumulate errors with if it failed. + * @param vb The third validation to accumulate errors with if it failed. + * @param vc The fourth validation to accumulate errors with if it failed. + * @param vd The fifth validation to accumulate errors with if it failed. + * @param ve The sixth validation to accumulate errors with if it failed. + * @param vf The seventh validation to accumulate errors with if it failed. + * @param vg The eighth validation to accumulate errors with if it failed. + * @return A Some if one or more validations failed (accumulated with the semigroup), otherwise, + * None. + */ + public Option accumulate(final Semigroup s, final Validation va, + final Validation vb, final Validation vc, + final Validation vd, final Validation ve, + final Validation vf, final Validation vg) { + return accumulate(s, va, vb, vc, vd, ve, vf, vg, new F8() { + public Unit f(final T t, final A a, final B b, final C c, final D d, final E$ e, final F$ f, final G g) { + return unit(); + } + }).f().toOption(); + } + + /** + * Returns an iterator for this validation. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this validation. + */ + public Iterator iterator() { + return toEither().right().iterator(); + } + + + public Validation, T> accumulate() { + if (isFail()) { + return Validation.fail(List.single(fail())); + } else { + return Validation.success(success()); + } + } + + public Validation, B> accumulate(F f) { + if (isFail()) { + return Validation.fail(List.single(fail())); + } else { + return Validation.success(f.f(success())); + } + } + + + public Validation, C> accumulate(Validation v2, F2 f) { + List list = List.nil(); + if (isFail()) { + list = list.cons(fail()); + } + if (v2.isFail()) { + list = list.cons(v2.fail()); + } + if (!list.isEmpty()) { + return Validation.fail(list); + } else { + return Validation.success(f.f(success(), v2.success())); + } + } + + + + public Validation, D> accumulate(Validation v2, Validation v3, F3 f) { + List list = fails(List.list(this, v2, v3)); + if (!list.isEmpty()) { + return Validation.fail(list); + } else { + return Validation.success(f.f(success(), v2.success(), v3.success())); + } + } + + public Validation, E> accumulate(Validation v2, Validation v3, Validation v4, F4 f) { + List list = fails(List.list(this, v2, v3, v4)); + if (!list.isEmpty()) { + return Validation.fail(list); + } else { + return Validation.success(f.f(success(), v2.success(), v3.success(), v4.success())); + } + } + + public Validation, $F> accumulate(Validation v2, Validation v3, Validation v4, Validation v5, F5 f) { + List list = fails(List.list(this, v2, v3, v4, v5)); + if (!list.isEmpty()) { + return Validation.fail(list); + } else { + return Validation.success(f.f(success(), v2.success(), v3.success(), v4.success(), v5.success())); + } + } + + + public Validation, G> accumulate(Validation v2, Validation v3, Validation v4, Validation v5, Validation v6, F6 f) { + List list = fails(List.list(this, v2, v3, v4, v5)); + if (!list.isEmpty()) { + return Validation.fail(list); + } else { + return Validation.success(f.f(success(), v2.success(), v3.success(), v4.success(), v5.success(), v6.success())); + } + } + + public Validation, H> accumulate(Validation v2, Validation v3, Validation v4, Validation v5, Validation v6, Validation v7, F7 f) { + List list = fails(List.list(this, v2, v3, v4, v5)); + if (!list.isEmpty()) { + return Validation.fail(list); + } else { + return Validation.success(f.f(success(), v2.success(), v3.success(), v4.success(), v5.success(), v6.success(), v7.success())); + } + } + + public Validation, I> accumulate(Validation v2, Validation v3, Validation v4, Validation v5, Validation v6, Validation v7, Validation v8, F8 f) { + List list = fails(List.list(this, v2, v3, v4, v5)); + if (!list.isEmpty()) { + return Validation.fail(list); + } else { + return Validation.success(f.f(success(), v2.success(), v3.success(), v4.success(), v5.success(), v6.success(), v7.success(), v8.success())); + } + } + + + + public static Validation, List> sequence(List> list) { + F2, Validation, List>, Validation, List>> f2 = (v, acc) -> { + if (acc.isFail() && v.isFail()) { + return Validation.validation(acc.toEither().left().map(l -> l.cons(v.fail()))); + } else if (acc.isSuccess() && v.isSuccess()) { + return acc.map(l -> l.cons(v.success())); + } else { + return acc; + } + }; + return list.foldRight(f2, Validation.success(List.nil())); + } + + + + public static List fails(List> list) { + return list.filter(v -> v.isFail()).map(v -> v.fail()); + } + + public static List successes(List> list) { + return list.filter(v -> v.isSuccess()).map(v -> v.success()); + } + + /** + * A failing projection of a validation. + */ + public final class FailProjection implements Iterable { + private final Validation v; + + private FailProjection(final Validation v) { + this.v = v; + } + + /** + * Returns the underlying validation. + * + * @return The underlying validation. + */ + public Validation validation() { + return v; + } + + /** + * Returns the failing value or fails with the given error message. + * + * @param err The error message to fail with. + * @return The failing value. + */ + public E failE(final P1 err) { + return v.toEither().left().valueE(err); + } + + /** + * Returns the failing value or fails with the given error message. + * + * @param err The error message to fail with. + * @return The failing value. + */ + public E failE(final String err) { + return failE(p(err)); + } + + /** + * Returns the failing value or the given value. + * + * @param e The value to return if this is success. + * @return The failing value or the given value. + */ + public E orFail(final P1 e) { + return v.toEither().left().orValue(e); + } + + /** + * Returns the failing value or the given value. + * + * @param e The value to return if this is success. + * @return The failing value or the given value. + */ + public E orFail(final E e) { + return orFail(p(e)); + } + + /** + * The failing value or the application of the given function to the success value. + * + * @param f The function to execute on the success value. + * @return The failing value or the application of the given function to the success value. + */ + public E on(final F f) { + return v.toEither().left().on(f); + } + + /** + * Executes a side-effect on the failing value if there is one. + * + * @param f The side-effect to execute. + * @return The unit value. + */ + public Unit foreach(final F f) { + return v.toEither().left().foreach(f); + } + + /** + * Executes a side-effect on the failing value if there is one. + * + * @param f The side-effect to execute. + */ + public void foreachDoEffect(final Effect1 f) { + v.toEither().left().foreachDoEffect(f); + } + + /** + * Maps the given function across the failing side of this validation. + * + * @param f The function to map. + * @return A new validation with the function mapped. + */ + public Validation map(final F f) { + return Validation.validation(v.toEither().left().map(f)); + } + + /** + * Binds the given function across this validation's failing value if it has one. + * + * @param f The function to bind across this validation. + * @return A new validation value after binding. + */ + public Validation bind(final F> f) { + return v.isFail() ? f.f(v.fail()) : Validation.success(v.success()); + } + + /** + * Performs a bind across the validation, but ignores the element value in the function. + * + * @param v The validation value to apply in the final join. + * @return A new validation value after the final join. + */ + public Validation sequence(final Validation v) { + return bind(new F>() { + public Validation f(final E e) { + return v; + } + }); + } + + + + + + + /** + * Returns None if this is a success or if the given predicate p does not hold for the + * failing value, otherwise, returns a fail in Some. + * + * @param f The predicate function to test on this failing value. + * @return None if this is a success or if the given predicate p does not hold for the + * failing value, otherwise, returns a fail in Some. + */ + public Option> filter(final F f) { + return v.toEither().left().filter(f).map(Validation.validation()); + } + + /** + * Function application on the failing value. + * + * @param v The validation of the function to apply on the failing value. + * @return The result of function application in validation. + */ + public Validation apply(final Validation, T> v) { + return v.f().bind(new F, Validation>() { + public Validation f(final F f) { + return map(f); + } + }); + } + + /** + * Returns true if this is a success or returns the result of the application of the given + * function to the failing value. + * + * @param f The predicate function to test on this failing value. + * @return true if this is a success or returns the result of the application of the given + * function to the failing value. + */ + public boolean forall(final F f) { + return v.toEither().left().forall(f); + } + + /** + * Returns false if this is a success or returns the result of the application of the given + * function to the failing value. + * + * @param f The predicate function to test on this failing value. + * @return false if this is a success or returns the result of the application of the given + * function to the failing value. + */ + public boolean exists(final F f) { + return v.toEither().left().exists(f); + } + + /** + * Returns a single element list if this is a failing value, otherwise an empty list. + * + * @return A single element list if this is a failing value, otherwise an empty list. + */ + public List toList() { + return v.toEither().left().toList(); + } + + /** + * Returns the failing value in Some if there is one, otherwise None. + * + * @return The failing value in Some if there is one, otherwise None. + */ + public Option toOption() { + return v.toEither().left().toOption(); + } + + /** + * Returns a single element array if this is a failing value, otherwise an empty list. + * + * @return A single element array if this is a failing value, otherwise an empty list. + */ + public Array toArray() { + return v.toEither().left().toArray(); + } + + /** + * Returns a single element stream if this is a failing value, otherwise an empty list. + * + * @return A single element stream if this is a failing value, otherwise an empty list. + */ + public Stream toStream() { + return v.toEither().left().toStream(); + } + + /** + * Returns an iterator for this projection. This method exists to permit the use in a for-each loop. + * + * @return A iterator for this projection. + */ + public Iterator iterator() { + return v.toEither().left().iterator(); + } + } + + /** + * Puts this validation's failing value in a non-empty list if there is one. + * + * @return A validation with its failing value in a non-empty list if there is one. + */ + @SuppressWarnings({"unchecked"}) + public Validation, T> nel() { + return isSuccess() ? + Validation., T>success(success()) : + Validation., T>fail(NonEmptyList.nel(fail())); + } + + /** + * Construct a validation using the given either value. + * + * @param e The either value to construct a validation with. + * @return A validation using the given either value. + */ + public static Validation validation(final Either e) { + return new Validation(e); + } + + /** + * Returns a function that constructs a validation with an either. + * + * @return A function that constructs a validation with an either. + */ + public static F, Validation> validation() { + return new F, Validation>() { + public Validation f(final Either e) { + return validation(e); + } + }; + } + + /** + * Returns a function that constructs an either with a validation. + * + * @return A function that constructs an either with a validation. + */ + public static F, Either> either() { + return new F, Either>() { + public Either f(final Validation v) { + return v.toEither(); + } + }; + } + + /** + * Returns a succeeding validation containing the given value. + * + * @param t The value to use in the succeeding validation. + * @return A succeeding validation containing the given value. + */ + public static Validation success(final T t) { + return validation(Either.right(t)); + } + + /** + * Returns a failing validation containing the given value. + * + * @param e The value to use in the failing validation. + * @return A failing validation containing the given value. + */ + public static Validation fail(final E e) { + return validation(Either.left(e)); + } + + /** + * Returns a failing validation containing a non-empty list that contains the given value. + * + * @param e The value to use in a non-empty list for the failing validation. + * @return A failing validation containing a non-empty list that contains the given value. + */ + public static Validation, T> failNEL(final E e) { + return fail(NonEmptyList.nel(e)); + } + + /** + * Returns a validation based on a boolean condition. If the condition is true, the validation succeeds, + * otherwise it fails. + * + * @param c The condition to base the returned validation on. + * @param e The failing value to use if the condition is false. + * @param t The succeeding value to use if the condition is true. + * @return A validation based on a boolean condition. + */ + public static Validation condition(final boolean c, final E e, final T t) { + return c ? Validation.success(t) : Validation.fail(e); + } + + /** + * Parses the given string into a byte. + * + * @param s The string to parse. + * @return A successfully parse byte or a failing exception. + */ + public static Validation parseByte(final String s) { + try { + return success(Byte.parseByte(s)); + } catch (NumberFormatException e) { + return fail(e); + } + } + + /** + * A function that parses a string into a byte. + */ + public static final F> parseByte = new F>() { + public Validation f(final String s) { + return parseByte(s); + } + }; + + /** + * Parses the given string into a double. + * + * @param s The string to parse. + * @return A successfully parse double or a failing exception. + */ + public static Validation parseDouble(final String s) { + try { + return success(Double.parseDouble(s)); + } catch (NumberFormatException e) { + return fail(e); + } + } + + /** + * A function that parses a string into a double. + */ + public static final F> parseDouble = new F>() { + public Validation f(final String s) { + return parseDouble(s); + } + }; + + /** + * Parses the given string into a float. + * + * @param s The string to parse. + * @return A successfully parse float or a failing exception. + */ + public static Validation parseFloat(final String s) { + try { + return success(Float.parseFloat(s)); + } catch (NumberFormatException e) { + return fail(e); + } + } + + /** + * A function that parses a string into a float. + */ + public static final F> parseFloat = new F>() { + public Validation f(final String s) { + return parseFloat(s); + } + }; + + /** + * Parses the given string into a integer. + * + * @param s The string to parse. + * @return A successfully parse integer or a failing exception. + */ + public static Validation parseInt(final String s) { + try { + return success(Integer.parseInt(s)); + } catch (NumberFormatException e) { + return fail(e); + } + } + + /** + * A function that parses a string into an integer. + */ + public static final F> parseInt = new F>() { + public Validation f(final String s) { + return parseInt(s); + } + }; + + /** + * Parses the given string into a long. + * + * @param s The string to parse. + * @return A successfully parse long or a failing exception. + */ + public static Validation parseLong(final String s) { + try { + return success(Long.parseLong(s)); + } catch (NumberFormatException e) { + return fail(e); + } + } + + /** + * A function that parses a string into a long. + */ + public static final F> parseLong = new F>() { + public Validation f(final String s) { + return parseLong(s); + } + }; + + /** + * Parses the given string into a short. + * + * @param s The string to parse. + * @return A successfully parse short or a failing exception. + */ + public static Validation parseShort(final String s) { + try { + return success(Short.parseShort(s)); + } catch (NumberFormatException e) { + return fail(e); + } + } + + /** + * A function that parses a string into a short. + */ + public static final F> parseShort = new F>() { + public Validation f(final String s) { + return parseShort(s); + } + }; + + public String toString() { + return Show.validationShow(Show.anyShow(), Show.anyShow()).showS(this); + } + + + + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Writer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Writer.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,65 @@ +package fj.data; + +import fj.*; + +/** + * Created by MarkPerry on 7/07/2014. + */ +public class Writer { + + private A val; + private W logValue; + private Monoid monoid; + + private Writer(A a, W w, Monoid m) { + val = a; + logValue = w; + monoid = m; + } + + public P2 run() { + return P.p(logValue, val); + } + + public A value() { + return val; + } + + public W log() { + return logValue; + } + + public Monoid monoid() { + return monoid; + } + + public static Writer unit(A a, W w, Monoid m) { + return new Writer(a, w, m); + } + + public static Writer unit(A a, Monoid m) { + return new Writer(a, m.zero(), m); + } + + public Writer tell(W w) { + return unit(val, monoid.sum(logValue, w), monoid); + } + + public Writer map(F f) { + return unit(f.f(val), logValue, monoid); + } + + public Writer flatMap(F> f) { + Writer writer = f.f(val); + return unit(writer.val, writer.monoid.sum(logValue, writer.logValue), writer.monoid); + } + + public static Writer unit(B b) { + return unit(b, Monoid.stringMonoid); + } + + public static F> stringLogger() { + return a -> Writer.unit(a, Monoid.stringMonoid); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/Zipper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/Zipper.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,619 @@ +package fj.data; + +import fj.Equal; +import fj.F; +import fj.F2; +import fj.F2Functions; +import fj.F3; +import fj.Function; +import fj.Ord; +import fj.P; +import fj.P1; +import fj.P2; +import fj.P3; +import fj.Show; +import fj.function.Integers; + +import java.util.Iterator; + +import static fj.Function.compose; +import static fj.Function.curry; +import static fj.Function.flip; +import static fj.Function.join; +import static fj.Function.uncurryF2; +import static fj.data.Option.none; +import static fj.data.Option.some; +import static fj.data.Stream.nil; +import static fj.data.Stream.repeat; +import static fj.F2Functions.*; + +/** + * Provides a pointed stream, which is a non-empty zipper-like stream structure that tracks an index (focus) + * position in a stream. Focus can be moved forward and backwards through the stream, elements can be inserted + * before or after the focused position, and the focused item can be deleted. + *

+ * Based on the pointedlist library by Jeff Wheeler. + */ +public final class Zipper implements Iterable> { + private final Stream left; + private final A focus; + private final Stream right; + + private Zipper(final Stream left, final A focus, final Stream right) { + this.left = left; + this.focus = focus; + this.right = right; + } + + + /** + * Creates a new Zipper with the given streams before and after the focus, and the given focused item. + * + * @param left The stream of elements before the focus. + * @param focus The element under focus. + * @param right The stream of elements after the focus. + * @return a new Zipper with the given streams before and after the focus, and the given focused item. + */ + public static Zipper zipper(final Stream left, final A focus, final Stream right) { + return new Zipper(left, focus, right); + } + + /** + * Creates a new Zipper from the given triple. + * + * @param p A triple of the elements before the focus, the focus element, and the elements after the focus, + * respectively. + * @return a new Zipper created from the given triple. + */ + public static Zipper zipper(final P3, A, Stream> p) { + return new Zipper(p._1(), p._2(), p._3()); + } + + /** + * First-class constructor of zippers. + * + * @return A function that yields a new zipper given streams on the left and right and a focus element. + */ + public static F3, A, Stream, Zipper> zipper() { + return new F3, A, Stream, Zipper>() { + public Zipper f(final Stream l, final A a, final Stream r) { + return zipper(l, a, r); + } + }; + } + + /** + * Returns the product-3 representation of this Zipper. + * + * @return the product-3 representation of this Zipper. + */ + public P3, A, Stream> p() { + return P.p(left, focus, right); + } + + /** + * A first-class function that yields the product-3 representation of a given Zipper. + * + * @return A first-class function that yields the product-3 representation of a given Zipper. + */ + public static F, P3, A, Stream>> p_() { + return new F, P3, A, Stream>>() { + public P3, A, Stream> f(final Zipper a) { + return a.p(); + } + }; + } + + /** + * An Ord instance for Zippers. + * + * @param o An Ord instance for the element type. + * @return An Ord instance for Zippers. + */ + public static Ord> ord(final Ord o) { + final Ord> so = Ord.streamOrd(o); + return Ord.p3Ord(so, o, so).comap(Zipper.p_()); + } + + /** + * An Equal instance for Zippers. + * + * @param e An Equal instance for the element type. + * @return An Equal instance for Zippers. + */ + public static Equal> eq(final Equal e) { + final Equal> se = Equal.streamEqual(e); + return Equal.p3Equal(se, e, se).comap(Zipper.p_()); + } + + /** + * A Show instance for Zippers. + * + * @param s A Show instance for the element type. + * @return A Show instance for Zippers. + */ + public static Show> show(final Show s) { + final Show> ss = Show.streamShow(s); + return Show.p3Show(ss, s, ss).comap(Zipper.p_()); + } + + /** + * Maps the given function across the elements of this zipper (covariant functor pattern). + * + * @param f A function to map across this zipper. + * @return A new zipper with the given function applied to all elements. + */ + public Zipper map(final F f) { + return zipper(left.map(f), f.f(focus), right.map(f)); + } + + /** + * Performs a right-fold reduction across this zipper. + * + * @param f The function to apply on each element of this zipper. + * @param z The beginning value to start the application from. + * @return the final result after the right-fold reduction. + */ + public B foldRight(final F> f, final B z) { + return left.foldLeft(flip(f), + right.cons(focus).foldRight(compose( + Function., B, B>andThen().f(P1.__1()), f), z)); + } + + /** + * Creates a new zipper with a single element. + * + * @param a The focus element of the new zipper. + * @return a new zipper with a single element which is in focus. + */ + public static Zipper single(final A a) { + return zipper(Stream.nil(), a, Stream.nil()); + } + + /** + * Possibly create a zipper if the provided stream has at least one element, otherwise None. + * The provided stream's head will be the focus of the zipper, and the rest of the stream will follow + * on the right side. + * + * @param a The stream from which to create a zipper. + * @return a new zipper if the provided stream has at least one element, otherwise None. + */ + @SuppressWarnings({"IfMayBeConditional"}) + public static Option> fromStream(final Stream a) { + if (a.isEmpty()) + return none(); + else + return some(zipper(Stream.nil(), a.head(), a.tail()._1())); + } + + /** + * Possibly create a zipper if the provided stream has at least one element, otherwise None. + * The provided stream's last element will be the focus of the zipper, following the rest of the stream in order, + * to the left. + * + * @param a The stream from which to create a zipper. + * @return a new zipper if the provided stream has at least one element, otherwise None. + */ + public static Option> fromStreamEnd(final Stream a) { + if (a.isEmpty()) + return none(); + else { + final Stream xs = a.reverse(); + return some(zipper(xs.tail()._1(), xs.head(), Stream.nil())); + } + } + + /** + * Returns the focus element of this zipper. + * + * @return the focus element of this zipper. + */ + public A focus() { + return focus; + } + + /** + * Possibly moves the focus to the next element in the list. + * + * @return An optional zipper with the focus moved one element to the right, if there are elements to the right of + * focus, otherwise None. + */ + public Option> next() { + return right.isEmpty() ? Option.>none() : some(tryNext()); + } + + /** + * Attempts to move the focus to the next element, or throws an error if there are no more elements. + * + * @return A zipper with the focus moved one element to the right, if there are elements to the right of + * focus, otherwise throws an error. + */ + public Zipper tryNext() { + if (right.isEmpty()) + throw new Error("Tried next at the end of a zipper."); + else + return zipper(left.cons(focus), right.head(), right.tail()._1()); + } + + /** + * Possibly moves the focus to the previous element in the list. + * + * @return An optional zipper with the focus moved one element to the left, if there are elements to the left of + * focus, otherwise None. + */ + public Option> previous() { + return left.isEmpty() ? Option.>none() : some(tryPrevious()); + } + + /** + * Attempts to move the focus to the previous element, or throws an error if there are no more elements. + * + * @return A zipper with the focus moved one element to the left, if there are elements to the left of + * focus, otherwise throws an error. + */ + public Zipper tryPrevious() { + if (left.isEmpty()) + throw new Error("Tried previous at the beginning of a zipper."); + else + return zipper(left.tail()._1(), left.head(), right.cons(focus)); + } + + /** + * First-class version of the next() function. + * + * @return A function that moves the given zipper's focus to the next element. + */ + public static F, Option>> next_() { + return new F, Option>>() { + public Option> f(final Zipper as) { + return as.next(); + } + }; + } + + /** + * First-class version of the previous() function. + * + * @return A function that moves the given zipper's focus to the previous element. + */ + public static F, Option>> previous_() { + return new F, Option>>() { + public Option> f(final Zipper as) { + return as.previous(); + } + }; + } + + /** + * Inserts an element to the left of the focus, then moves the focus to the new element. + * + * @param a A new element to insert into this zipper. + * @return A new zipper with the given element in focus, and the current focus element on its right. + */ + public Zipper insertLeft(final A a) { + return zipper(left, a, right.cons(focus)); + } + + /** + * Inserts an element to the right of the focus, then moves the focus to the new element. + * + * @param a A new element to insert into this zipper. + * @return A new zipper with the given element in focus, and the current focus element on its left. + */ + public Zipper insertRight(final A a) { + return zipper(left.cons(focus), a, right); + } + + /** + * Possibly deletes the element at the focus, then moves the element on the left into focus. + * If no element is on the left, focus on the element to the right. + * Returns None if the focus element is the only element in this zipper. + * + * @return A new zipper with this zipper's focus element removed, or None if deleting the focus element + * would cause the zipper to be empty. + */ + public Option> deleteLeft() { + return left.isEmpty() && right.isEmpty() + ? Option.>none() + : some(zipper(left.isEmpty() ? left : left.tail()._1(), + left.isEmpty() ? right.head() : left.head(), + left.isEmpty() ? right.tail()._1() : right)); + } + + /** + * Possibly deletes the element at the focus, then moves the element on the right into focus. + * If no element is on the right, focus on the element to the left. + * Returns None if the focus element is the only element in this zipper. + * + * @return A new zipper with this zipper's focus element removed, or None if deleting the focus element + * would cause the zipper to be empty. + */ + public Option> deleteRight() { + return left.isEmpty() && right.isEmpty() + ? Option.>none() + : some(zipper(right.isEmpty() ? left.tail()._1() : left, + right.isEmpty() ? left.head() : right.head(), + right.isEmpty() ? right : right.tail()._1())); + } + + /** + * Deletes all elements in the zipper except the focus. + * + * @return A new zipper with the focus element as the only element. + */ + public Zipper deleteOthers() { + final Stream nil = nil(); + return zipper(nil, focus, nil); + } + + /** + * Returns the length of this zipper. + * + * @return the length of this zipper. + */ + public int length() { + return foldRight(Function.>constant(Integers.add.f(1)), 0); + } + + /** + * Returns whether the focus is on the first element. + * + * @return true if the focus is on the first element, otherwise false. + */ + public boolean atStart() { + return left.isEmpty(); + } + + /** + * Returns whether the focus is on the last element. + * + * @return true if the focus is on the last element, otherwise false. + */ + public boolean atEnd() { + return right.isEmpty(); + } + + /** + * Creates a zipper of variations of this zipper, in which each element is focused, + * with this zipper as the focus of the zipper of zippers (comonad pattern). + * + * @return a zipper of variations of the provided zipper, in which each element is focused, + * with this zipper as the focus of the zipper of zippers. + */ + public Zipper> positions() { + final Stream> left = Stream.unfold( + new F, Option, Zipper>>>() { + public Option, Zipper>> f(final Zipper p) { + return p.previous().map(join(P., Zipper>p2())); + } + }, this); + final Stream> right = Stream.unfold( + new F, Option, Zipper>>>() { + public Option, Zipper>> f(final Zipper p) { + return p.next().map(join(P., Zipper>p2())); + } + }, this); + + return zipper(left, this, right); + } + + /** + * Maps over variations of this zipper, such that the given function is applied to each variation (comonad pattern). + * + * @param f The comonadic function to apply for each variation of this zipper. + * @return A new zipper, with the given function applied for each variation of this zipper. + */ + public Zipper cobind(final F, B> f) { + return positions().map(f); + } + + /** + * Zips the elements of this zipper with a boolean that indicates whether that element has focus. + * All of the booleans will be false, except the focused element. + * + * @return A new zipper of pairs, with each element of this zipper paired with a boolean that is true if that + * element has focus, and false otherwise. + */ + public Zipper> zipWithFocus() { + return zipper(left.zip(repeat(false)), P.p(focus, true), right.zip(repeat(false))); + } + + /** + * Move the focus to the specified index. + * + * @param n The index to which to move the focus. + * @return A new zipper with the focus moved to the specified index, or none if there is no such index. + */ + public Option> move(final int n) { + final int ll = left.length(); + final int rl = right.length(); + Option> p = some(this); + if (n < 0 || n >= length()) + return none(); + else if (ll >= n) + for (int i = ll - n; i > 0; i--) + p = p.bind(Zipper.previous_()); + else if (rl >= n) + for (int i = rl - n; i > 0; i--) + p = p.bind(Zipper.next_()); + return p; + } + + /** + * A first-class version of the move function. + * + * @return A function that moves the focus of the given zipper to the given index. + */ + public static F, Option>>> move() { + return curry(new F2, Option>>() { + public Option> f(final Integer i, final Zipper a) { + return a.move(i); + } + }); + } + + /** + * Moves the focus to the element matching the given predicate, if present. + * + * @param p A predicate to match. + * @return A new zipper with the nearest matching element focused if it is present in this zipper. + */ + public Option> find(final F p) { + if (p.f(focus())) + return some(this); + else { + final Zipper> ps = positions(); + return ps.lefts().interleave(ps.rights()).find(new F, Boolean>() { + public Boolean f(final Zipper zipper) { + return p.f(zipper.focus()); + } + }); + } + } + + /** + * Returns the index of the focus. + * + * @return the index of the focus. + */ + public int index() { + return left.length(); + } + + /** + * Move the focus to the next element. If the last element is focused, loop to the first element. + * + * @return A new zipper with the next element focused, unless the last element is currently focused, in which case + * the first element becomes focused. + */ + public Zipper cycleNext() { + if (left.isEmpty() && right.isEmpty()) + return this; + else if (right.isEmpty()) { + final Stream xs = left.reverse(); + return zipper(Stream.nil(), xs.head(), xs.tail()._1().snoc(P.p(focus))); + } else + return tryNext(); + } + + /** + * Move the focus to the previous element. If the first element is focused, loop to the last element. + * + * @return A new zipper with the previous element focused, unless the first element is currently focused, + * in which case the last element becomes focused. + */ + public Zipper cyclePrevious() { + if (left.isEmpty() && right.isEmpty()) + return this; + else if (left.isEmpty()) { + final Stream xs = right.reverse(); + return zipper(xs.tail()._1().snoc(P.p(focus)), xs.head(), Stream.nil()); + } else + return tryPrevious(); + } + + /** + * Possibly deletes the element at the focus, then move the element on the left into focus. If no element is on the + * left, focus on the last element. If the deletion will cause the list to be empty, return None. + * + * @return A new zipper with the focused element removed, and focus on the previous element to the left, or the last + * element if there is no element to the left. + */ + public Option> deleteLeftCycle() { + if (left.isEmpty() && right.isEmpty()) + return none(); + else if (left.isNotEmpty()) + return some(zipper(left.tail()._1(), left.head(), right)); + else { + final Stream xs = right.reverse(); + return some(zipper(xs.tail()._1(), xs.head(), Stream.nil())); + } + } + + /** + * Possibly deletes the element at the focus, then move the element on the right into focus. If no element is on the + * right, focus on the first element. If the deletion will cause the list to be empty, return None. + * + * @return A new zipper with the focused element removed, and focus on the next element to the right, or the first + * element if there is no element to the right. + */ + public Option> deleteRightCycle() { + if (left.isEmpty() && right.isEmpty()) + return none(); + else if (right.isNotEmpty()) + return some(zipper(left, right.head(), right.tail()._1())); + else { + final Stream xs = left.reverse(); + return some(zipper(Stream.nil(), xs.head(), xs.tail()._1())); + } + } + + /** + * Replaces the element in focus with the given element. + * + * @param a An element to replace the focused element with. + * @return A new zipper with the given element in focus. + */ + public Zipper replace(final A a) { + return zipper(left, a, right); + } + + /** + * Returns the Stream representation of this zipper. + * + * @return A stream that contains all the elements of this zipper. + */ + public Stream toStream() { + return left.reverse().snoc(P.p(focus)).append(right); + } + + /** + * Returns a Stream of the elements to the left of focus. + * + * @return a Stream of the elements to the left of focus. + */ + public Stream lefts() { + return left; + } + + /** + * Returns a Stream of the elements to the right of focus. + * + * @return a Stream of the elements to the right of focus. + */ + public Stream rights() { + return right; + } + + /** + * Zips this Zipper with another, applying the given function lock-step over both zippers in both directions. + * The structure of the resulting Zipper is the structural intersection of the two Zippers. + * + * @param bs A Zipper to zip this one with. + * @param f A function with which to zip together the two Zippers. + * @return The result of applying the given function over this Zipper and the given Zipper, location-wise. + */ + public Zipper zipWith(final Zipper bs, final F2 f) { + return F2Functions.zipZipperM(f).f(this, bs); + } + + + /** + * Zips this Zipper with another, applying the given function lock-step over both zippers in both directions. + * The structure of the resulting Zipper is the structural intersection of the two Zippers. + * + * @param bs A Zipper to zip this one with. + * @param f A function with which to zip together the two Zippers. + * @return The result of applying the given function over this Zipper and the given Zipper, location-wise. + */ + public Zipper zipWith(final Zipper bs, final F> f) { + return zipWith(bs, uncurryF2(f)); + } + + /** + * Returns an iterator of all the positions of this Zipper, starting from the leftmost position. + * + * @return An iterator of all the positions of this Zipper, starting from the leftmost position. + */ + public Iterator> iterator() { return positions().toStream().iterator(); } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/Deep.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/Deep.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,851 @@ +package fj.data.fingertrees; + +import fj.F; +import fj.Function; +import fj.P2; +import fj.data.vector.V2; +import fj.data.vector.V3; +import fj.data.vector.V4; +import static fj.data.List.list; +import static fj.Function.flip; + +/** + * A finger tree with 1-4-digits on the left and right, and a finger tree of 2-3-nodes in the middle. + */ +public final class Deep extends FingerTree { + private final V v; + private final Digit prefix; + private final FingerTree> middle; + private final Digit suffix; + + Deep(final Measured m, final V v, final Digit prefix, + final FingerTree> middle, + final Digit suffix) { + super(m); + this.v = v; + this.prefix = prefix; + this.middle = middle; + this.suffix = suffix; + } + + /** + * Returns the first few elements of this tree. + * + * @return the first few elements of this tree. + */ + public Digit prefix() { + return prefix; + } + + /** + * Returns a finger tree of the inner nodes of this tree. + * + * @return a finger tree of the inner nodes of this tree. + */ + public FingerTree> middle() { + return middle; + } + + /** + * Returns the last few elements of this tree. + * + * @return the last few elements of this tree. + */ + public Digit suffix() { + return suffix; + } + + @Override public B foldRight(final F> aff, final B z) { + return prefix.foldRight(aff, middle.foldRight(flip(Node.foldRight_(aff)), suffix.foldRight(aff, z))); + } + + @Override public A reduceRight(final F> aff) { + return prefix.foldRight(aff, middle.foldRight(flip(Node.foldRight_(aff)), suffix.reduceRight(aff))); + } + + @Override public B foldLeft(final F> bff, final B z) { + return suffix.foldLeft(bff, middle.foldLeft(Node.foldLeft_(bff), prefix.foldLeft(bff, z))); + } + + @Override public A reduceLeft(final F> aff) { + return suffix.foldLeft(aff, middle.foldLeft(Node.foldLeft_(aff), prefix.reduceLeft(aff))); + } + + @Override public FingerTree map(final F abf, final Measured m) { + return new Deep(m, v, prefix.map(abf, m), middle.map(Node.liftM(abf, m), m.nodeMeasured()), + suffix.map(abf, m)); + } + + /** + * Returns the sum of the measurements of this tree's elements, according to the monoid. + * + * @return the sum of the measurements of this tree's elements, according to the monoid. + */ + public V measure() { + return v; + } + + /** + * Pattern matching on the tree. Matches the function on the Deep tree. + */ + @Override public B match(final F, B> empty, final F, B> single, + final F, B> deep) { + return deep.f(this); + } + + @Override public FingerTree cons(final A a) { + final Measured m = measured(); + final V measure = m.sum(m.measure(a), v); + final MakeTree mk = mkTree(m); + return prefix.match(new F, FingerTree>() { + public FingerTree f(final One one) { + return new Deep(m, measure, mk.two(a, one.value()), middle, suffix); + } + }, new F, FingerTree>() { + public FingerTree f(final Two two) { + return new Deep(m, measure, mk.three(a, two.values()._1(), two.values()._2()), middle, suffix); + } + }, new F, FingerTree>() { + public FingerTree f(final Three three) { + return new Deep(m, measure, mk.four(a, three.values()._1(), three.values()._2(), + three.values()._3()), middle, suffix); + } + }, new F, FingerTree>() { + public FingerTree f(final Four four) { + return new Deep(m, measure, mk.two(a, four.values()._1()), + middle.cons(mk.node3(four.values()._2(), four.values()._3(), four.values()._4())), + suffix); + } + }); + } + + public FingerTree snoc(final A a) { + final Measured m = measured(); + final V measure = m.sum(m.measure(a), v); + final MakeTree mk = mkTree(m); + return suffix.match(new F, FingerTree>() { + public FingerTree f(final One one) { + return new Deep(m, measure, prefix, middle, mk.two(one.value(), a)); + } + }, new F, FingerTree>() { + public FingerTree f(final Two two) { + return new Deep(m, measure, prefix, middle, mk.three(two.values()._1(), two.values()._2(), a)); + } + }, new F, FingerTree>() { + public FingerTree f(final Three three) { + return new Deep(m, measure, prefix, middle, mk.four(three.values()._1(), three.values()._2(), + three.values()._3(), a)); + } + }, new F, FingerTree>() { + public FingerTree f(final Four four) { + return new Deep(m, measure, prefix, + middle.snoc(mk.node3(four.values()._1(), four.values()._2(), four.values()._3())), + mk.two(four.values()._4(), a)); + } + }); + } + + @Override public FingerTree append(final FingerTree t) { + final Measured m = measured(); + return t.match(Function., FingerTree>constant(t), new F, FingerTree>() { + public FingerTree f(final Single single) { + return t.snoc(single.value()); + } + }, new F, FingerTree>() { + public FingerTree f(final Deep deep) { + return new Deep(m, m.sum(measure(), deep.measure()), prefix, + addDigits0(m, middle, suffix, deep.prefix, deep.middle), deep.suffix); + } + }); + } + + @SuppressWarnings({"ReturnOfNull", "IfStatementWithIdenticalBranches"}) + @Override public P2 lookup(final F o, final int i) { + final int spr = o.f(prefix.measure()); + final int spm = o.f(middle.measure()); + if (i < spr) + return null; // TODO + //return prefix.lookup(o, i); + if (i < spm) { + return null; // TODO + /* final P2> p = middle.lookup(o, i - spr); + return p._2().lookup(o, p._1()); */ + } + return null; // TODO suffix.lookup(i - spm); + } + + private static FingerTree> addDigits0(final Measured m, final FingerTree> m1, + final Digit s1, final Digit p2, + final FingerTree> m2) { + final MakeTree mk = mkTree(m); + return s1.match(new F, FingerTree>>() { + public FingerTree> f(final One one1) { + return p2.match(new F, FingerTree>>() { + public FingerTree> f(final One one2) { + return append1(m, m1, mk.node2(one1.value(), one2.value()), m2); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Two two2) { + final V2 vs = two2.values(); + return append1(m, m1, mk.node3(one1.value(), vs._1(), vs._2()), m2); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Three three) { + final V3 vs = three.values(); + return append2(m, m1, mk.node2(one1.value(), vs._1()), mk.node2(vs._2(), vs._3()), m2); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Four four) { + final V4 vs = four.values(); + return append2(m, m1, mk.node3(one1.value(), vs._1(), vs._2()), mk.node2(vs._3(), vs._4()), m2); + } + }); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Two two1) { + final V2 v1 = two1.values(); + return p2.match(new F, FingerTree>>() { + public FingerTree> f(final One one) { + return append1(m, m1, mk.node3(v1._1(), v1._2(), one.value()), m2); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Two two2) { + final V2 v2 = two2.values(); + return append2(m, m1, mk.node2(v1._1(), v1._2()), mk.node2(v2._1(), v2._2()), m2); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Three three) { + final V3 v2 = three.values(); + return append2(m, m1, mk.node3(v1._1(), v1._2(), v2._1()), mk.node2(v2._2(), v2._3()), m2); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Four four) { + final V4 v2 = four.values(); + return append2(m, m1, mk.node3(v1._1(), v1._2(), v2._1()), mk.node3(v2._2(), v2._3(), v2._4()), m2); + } + }); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Three three1) { + final V3 v1 = three1.values(); + return p2.match(new F, FingerTree>>() { + public FingerTree> f(final One one) { + return append2(m, m1, mk.node2(v1._1(), v1._2()), mk.node2(v1._3(), one.value()), m2); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Two two) { + final V2 v2 = two.values(); + return append2(m, m1, mk.node3(v1), mk.node2(v2), m2); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Three three2) { + return append2(m, m1, mk.node3(v1), mk.node3(three2.values()), m2); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Four four) { + return append3(m, m1, mk.node3(v1), mk.node2(four.values()._1(), four.values()._2()), + mk.node2(four.values()._3(), four.values()._4()), m2); + } + }); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Four four1) { + final V4 v1 = four1.values(); + return p2.match(new F, FingerTree>>() { + public FingerTree> f(final One one) { + return append2(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node2(v1._4(), one.value()), m2); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Two two) { + final V2 v2 = two.values(); + return append2(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), v2._1(), v2._2()), m2); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Three three) { + final V3 v2 = three.values(); + return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node2(v1._4(), v2._1()), + mk.node2(v2._2(), v2._3()), m2); + } + }, new F, FingerTree>>() { + public FingerTree> f(final Four four2) { + final V4 v2 = four2.values(); + return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), v2._1(), v2._2()), + mk.node2(v2._3(), v2._4()), m2); + } + }); + } + }); + } + + private static FingerTree> append1(final Measured m, final FingerTree> xs, + final Node a, final FingerTree> ys) { + return xs.match(new F>, FingerTree>>() { + public FingerTree> f(final Empty> empty) { + return ys.cons(a); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Single> single) { + return ys.cons(a).cons(single.value()); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Deep> deep1) { + return ys.match(new F>, FingerTree>>() { + public FingerTree> f(final Empty> empty) { + return xs.snoc(a); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Single> single) { + return xs.snoc(a).snoc(single.value()); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Deep> deep2) { + final Measured> nm = m.nodeMeasured(); + return new Deep>(nm, m.sum(m.sum(deep1.v, nm.measure(a)), deep2.v), deep1.prefix, + addDigits1(nm, deep1.middle, deep1.suffix, a, deep2.prefix, deep2.middle), + deep2.suffix); + } + }); + } + }); + } + + private static FingerTree>> addDigits1(final Measured> m, + final FingerTree>> m1, + final Digit> x, final Node n, + final Digit> y, + final FingerTree>> m2) { + final MakeTree> mk = mkTree(m); + return x.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one1) { + return y.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one2) { + return append1(m, m1, mk.node3(one1.value(), n, one2.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + return append2(m, m1, mk.node2(one1.value(), n), mk.node2(two.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + final V3> v2 = three.values(); + return append2(m, m1, mk.node3(one1.value(), n, v2._1()), mk.node2(v2._2(), v2._3()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append2(m, m1, mk.node3(one1.value(), n, v2._1()), mk.node3(v2._2(), v2._3(), v2._4()), m2); + } + }); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two1) { + final V2> v1 = two1.values(); + return y.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return append2(m, m1, mk.node2(v1), mk.node2(n, one.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + return append2(m, m1, mk.node3(v1._1(), v1._2(), n), mk.node2(two.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + return append2(m, m1, mk.node3(v1._1(), v1._2(), n), mk.node3(three.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append3(m, m1, mk.node3(v1._1(), v1._2(), n), mk.node2(v2._1(), v2._2()), mk.node2(v2._3(), v2._4()), + m2); + } + }); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + final V3> v1 = three.values(); + return y.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return append2(m, m1, mk.node3(v1), mk.node2(n, one.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + final V2> v2 = two.values(); + return append2(m, m1, mk.node3(v1), mk.node3(n, v2._1(), v2._2()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + final V3> v2 = three.values(); + return append3(m, m1, mk.node3(v1), mk.node2(n, v2._1()), mk.node2(v2._2(), v2._3()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append3(m, m1, mk.node3(v1), mk.node3(n, v2._1(), v2._2()), mk.node2(v2._3(), v2._4()), m2); + } + }); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v1 = four.values(); + return y.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return append2(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n, one.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node2(v1._4(), n), mk.node2(two.values()), + m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + final V3> v2 = three.values(); + return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n, v2._1()), + mk.node2(v2._2(), v2._3()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n, v2._1()), + mk.node3(v2._2(), v2._3(), v2._4()), m2); + } + }); + } + }); + } + + private static FingerTree> append2(final Measured m, final FingerTree> t1, + final Node n1, final Node n2, + final FingerTree> t2) { + return t1.match(new F>, FingerTree>>() { + public FingerTree> f(final Empty> empty) { + return t2.cons(n2).cons(n1); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Single> single) { + return t2.cons(n2).cons(n1).cons(single.value()); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Deep> deep) { + return t2.match(new F>, FingerTree>>() { + public FingerTree> f(final Empty> empty) { + return deep.snoc(n1).snoc(n2); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Single> single) { + return deep.snoc(n1).snoc(n2).snoc(single.value()); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Deep> deep2) { + return new Deep>(m.nodeMeasured(), + m.sum(m.sum(m.sum(deep.measure(), n1.measure()), n2.measure()), + deep2.measure()), deep.prefix, + addDigits2(m.nodeMeasured(), deep.middle, deep.suffix, n1, n2, deep2.prefix, + deep2.middle), deep2.suffix); + } + }); + } + }); + } + + private static FingerTree>> addDigits2(final Measured> m, + final FingerTree>> m1, + final Digit> suffix, + final Node n1, final Node n2, + final Digit> prefix, + final FingerTree>> m2) { + final MakeTree> mk = mkTree(m); + return suffix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return prefix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one2) { + return append2(m, m1, mk.node2(one.value(), n1), mk.node2(n2, one2.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + return append2(m, m1, mk.node3(one.value(), n1, n2), mk.node2(two.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + return append2(m, m1, mk.node3(one.value(), n1, n2), mk.node3(three.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append3(m, m1, mk.node3(one.value(), n1, n2), mk.node2(v2._1(), v2._2()), mk.node2(v2._3(), v2._4()), + m2); + } + }); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + final V2> v1 = two.values(); + return prefix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return append2(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node2(n2, one.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two2) { + final V2> v2 = two2.values(); + return append2(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, v2._1(), v2._2()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + final V3> v2 = three.values(); + return append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node2(n2, v2._1()), mk.node2(v2._2(), v2._3()), + m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, v2._1(), v2._2()), + mk.node2(v2._3(), v2._4()), m2); + } + }); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + final V3> v1 = three.values(); + return prefix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return append2(m, m1, mk.node3(v1), mk.node3(n1, n2, one.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + return append3(m, m1, mk.node3(v1), mk.node2(n1, n2), mk.node2(two.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three2) { + final V3> v2 = three2.values(); + return append3(m, m1, mk.node3(v1), mk.node3(n1, n2, v2._1()), mk.node2(v2._2(), v2._3()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append3(m, m1, mk.node3(v1), mk.node3(n1, n2, v2._1()), mk.node3(v2._2(), v2._3(), v2._4()), m2); + } + }); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v1 = four.values(); + return prefix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node2(v1._4(), n1), mk.node2(n2, one.value()), + m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2), + mk.node2(two.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2), + mk.node3(three.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four2) { + final V4> v2 = four2.values(); + return append4(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2), + mk.node2(v2._1(), v2._2()), mk.node2(v2._3(), v2._4()), m2); + } + }); + } + }); + } + + @SuppressWarnings("unchecked") + private static FingerTree> append3(final Measured m, final FingerTree> t1, + final Node n1, final Node n2, final Node n3, + final FingerTree> t2) { + final Measured> nm = m.nodeMeasured(); + return t1.match(new F>, FingerTree>>() { + public FingerTree> f(final Empty> empty) { + return t2.cons(n3).cons(n2).cons(n1); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Single> single) { + return t2.cons(n3).cons(n2).cons(n1).cons(single.value()); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Deep> deep) { + return t2.match(new F>, FingerTree>>() { + public FingerTree> f(final Empty> empty) { + return deep.snoc(n1).snoc(n2).snoc(n3); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Single> single) { + return deep.snoc(n1).snoc(n2).snoc(n3).snoc(single.value()); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Deep> deep2) { + return new Deep>(nm, nm.monoid().sumLeft( + list(deep.v, n1.measure(), n2.measure(), n3.measure(), deep2.v)), deep.prefix, + addDigits3(nm, deep.middle, deep.suffix, n1, n2, n3, deep2.prefix, + deep2.middle), deep2.suffix); + } + }); + } + }); + } + + private static FingerTree>> addDigits3(final Measured> m, + final FingerTree>> m1, + final Digit> suffix, + final Node n1, final Node n2, + final Node n3, + final Digit> prefix, + final FingerTree>> m2) { + final MakeTree> mk = mkTree(m); + return suffix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return prefix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one2) { + return append2(m, m1, mk.node3(one.value(), n1, n2), mk.node2(n3, one2.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + final V2> v2 = two.values(); + return append2(m, m1, mk.node3(one.value(), n1, n2), mk.node3(n3, v2._1(), v2._2()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + final V3> v2 = three.values(); + return append3(m, m1, mk.node3(one.value(), n1, n2), mk.node2(n3, v2._1()), mk.node2(v2._2(), v2._3()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append3(m, m1, mk.node3(one.value(), n1, n2), mk.node3(n3, v2._1(), v2._2()), + mk.node2(v2._3(), v2._4()), m2); + } + }); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + final V2> v1 = two.values(); + return prefix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return append2(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, n3, one.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + return append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node2(n2, n3), mk.node2(two.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + final V3> v2 = three.values(); + return append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, n3, v2._1()), mk.node2(v2._2(), v2._3()), + m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, n3, v2._1()), + mk.node3(v2._2(), v2._3(), v2._4()), m2); + } + }); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + return prefix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return append3(m, m1, mk.node3(three.values()), mk.node2(n1, n2), mk.node2(n3, one.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + return append3(m, m1, mk.node3(three.values()), mk.node3(n1, n2, n3), mk.node2(two.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three2) { + return append3(m, m1, mk.node3(three.values()), mk.node3(n1, n2, n3), mk.node3(three2.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append4(m, m1, mk.node3(three.values()), mk.node3(n1, n2, n3), mk.node2(v2._1(), v2._2()), + mk.node2(v2._3(), v2._4()), m2); + } + }); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v1 = four.values(); + return prefix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2), + mk.node2(n3, one.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + final V2> v2 = two.values(); + return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2), + mk.node3(n3, v2._1(), v2._2()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + final V3> v2 = three.values(); + return append4(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2), mk.node2(n3, v2._1()), + mk.node2(v2._2(), v2._3()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four2) { + final V4> v2 = four2.values(); + return append4(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2), + mk.node3(n3, v2._1(), v2._2()), mk.node2(v2._3(), v2._4()), m2); + } + }); + } + }); + } + + @SuppressWarnings("unchecked") + private static FingerTree> append4(final Measured m, + final FingerTree> t1, + final Node n1, + final Node n2, + final Node n3, + final Node n4, + final FingerTree> t2) { + final Measured> nm = m.nodeMeasured(); + return t1.match(new F>, FingerTree>>() { + public FingerTree> f(final Empty> empty) { + return t2.cons(n4).cons(n3).cons(n2).cons(n1); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Single> single) { + return t2.cons(n4).cons(n3).cons(n2).cons(n1).cons(single.value()); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Deep> deep) { + return t2.match(new F>, FingerTree>>() { + public FingerTree> f(final Empty> empty) { + return t1.snoc(n1).snoc(n2).snoc(n3).snoc(n4); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Single> single) { + return t1.snoc(n1).snoc(n2).snoc(n3).snoc(n4).snoc(single.value()); + } + }, new F>, FingerTree>>() { + public FingerTree> f(final Deep> deep2) { + return new Deep>(nm, m.monoid().sumLeft( + list(deep.v, n1.measure(), n2.measure(), n3.measure(), n4.measure(), deep2.v)), deep.prefix, + addDigits4(nm, deep.middle, deep.suffix, n1, n2, n3, n4, deep2.prefix, + deep2.middle), deep2.suffix); + } + }); + } + }); + } + + private static FingerTree>> addDigits4(final Measured> m, + final FingerTree>> m1, + final Digit> suffix, + final Node n1, final Node n2, + final Node n3, final Node n4, + final Digit> prefix, + final FingerTree>> m2) { + final MakeTree> mk = mkTree(m); + return suffix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return prefix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one2) { + return append2(m, m1, mk.node3(one.value(), n1, n2), mk.node3(n3, n4, one2.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + return append3(m, m1, mk.node3(one.value(), n1, n2), mk.node2(n3, n4), mk.node2(two.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + final V3> v2 = three.values(); + return append3(m, m1, mk.node3(one.value(), n1, n2), mk.node3(n3, n4, v2._1()), mk.node2(v2._2(), v2._3()), + m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append3(m, m1, mk.node3(one.value(), n1, n2), mk.node3(n3, n4, v2._1()), + mk.node3(v2._2(), v2._3(), v2._4()), m2); + } + }); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + final V2> v1 = two.values(); + return prefix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node2(n2, n3), mk.node2(n4, one.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two2) { + return append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, n3, n4), mk.node2(two2.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + return append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, n3, n4), mk.node3(three.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append4(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, n3, n4), mk.node2(v2._1(), v2._2()), + mk.node2(v2._3(), v2._4()), m2); + } + }); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + final V3> v1 = three.values(); + return prefix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return append3(m, m1, mk.node3(v1), mk.node3(n1, n2, n3), mk.node2(n4, one.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + final V2> v2 = two.values(); + return append3(m, m1, mk.node3(v1), mk.node3(n1, n2, n3), mk.node3(n4, v2._1(), v2._2()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + final V3> v2 = three.values(); + return append4(m, m1, mk.node3(v1), mk.node3(n1, n2, n3), mk.node2(n4, v2._1()), mk.node2(v2._2(), v2._3()), + m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append4(m, m1, mk.node3(v1), mk.node3(n1, n2, n3), mk.node3(n4, v2._1(), v2._2()), + mk.node2(v2._3(), v2._4()), m2); + } + }); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v1 = four.values(); + return prefix.match(new F>, FingerTree>>>() { + public FingerTree>> f(final One> one) { + return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2), + mk.node3(n3, n4, one.value()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Two> two) { + return append4(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2), + mk.node2(n3, n4), mk.node2(two.values()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Three> three) { + final V3> v2 = three.values(); + return append4(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2), + mk.node3(n3, n4, v2._1()), mk.node2(v2._2(), v2._3()), m2); + } + }, new F>, FingerTree>>>() { + public FingerTree>> f(final Four> four) { + final V4> v2 = four.values(); + return append4(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2), + mk.node3(n3, n4, v2._1()), mk.node3(v2._2(), v2._3(), v2._4()), m2); + } + }); + } + }); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/Digit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/Digit.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,176 @@ +package fj.data.fingertrees; + +import fj.F; +import fj.F2; +import fj.Function; +import fj.data.vector.V2; +import fj.data.vector.V3; +import fj.data.vector.V4; +import static fj.data.fingertrees.FingerTree.mkTree; + +/** + * A digit is a vector of 1-4 elements. Serves as a pointer to the prefix or suffix of a finger tree. + */ +public abstract class Digit { + /** + * Folds this digit to the right using the given function and the given initial value. + * + * @param f A function with which to fold this digit. + * @param z An initial value to apply at the rightmost end of the fold. + * @return The right reduction of this digit with the given function and the given initial value. + */ + public abstract B foldRight(final F> f, final B z); + + /** + * Folds this digit to the left using the given function and the given initial value. + * + * @param f A function with which to fold this digit. + * @param z An initial value to apply at the leftmost end of the fold. + * @return The left reduction of this digit with the given function and the given initial value. + */ + public abstract B foldLeft(final F> f, final B z); + + /** + * Folds this digit to the right using the given function. + * + * @param f A function with which to fold this digit. + * @return The right reduction of this digit with the given function. + */ + public final A reduceRight(final F> f) { + return match(new F, A>() { + public A f(final One one) { + return one.value(); + } + }, new F, A>() { + public A f(final Two two) { + final V2 v = two.values(); + return f.f(v._1()).f(v._2()); + } + }, new F, A>() { + public A f(final Three three) { + final V3 v = three.values(); + return f.f(v._1()).f(f.f(v._2()).f(v._3())); + } + }, new F, A>() { + public A f(final Four four) { + final V4 v = four.values(); + return f.f(v._1()).f(f.f(v._2()).f(f.f(v._3()).f(v._4()))); + } + }); + } + + /** + * Folds this digit to the right using the given function. + * + * @param f A function with which to fold this digit. + * @return The right reduction of this digit with the given function. + */ + public final A reduceLeft(final F> f) { + return match(new F, A>() { + public A f(final One one) { + return one.value(); + } + }, new F, A>() { + public A f(final Two two) { + final V2 v = two.values(); + return f.f(v._1()).f(v._2()); + } + }, new F, A>() { + public A f(final Three three) { + final V3 v = three.values(); + return f.f(f.f(v._1()).f(v._2())).f(v._3()); + } + }, new F, A>() { + public A f(final Four four) { + final V4 v = four.values(); + return f.f(f.f(f.f(v._1()).f(v._2())).f(v._3())).f(v._4()); + } + }); + } + + /** + * Maps a function across the elements of this digit, measuring with the given measurement. + * + * @param f A function to map across the elements of this digit. + * @param m A measuring for the function's domain (destination type). + * @return A new digit with the same structure as this digit, but with all elements transformed + * with the given function and measured with the given measuring. + */ + public final Digit map(final F f, final Measured m) { + return match(new F, Digit>() { + public Digit f(final One one) { + return new One(m, f.f(one.value())); + } + }, new F, Digit>() { + public Digit f(final Two two) { + return new Two(m, two.values().map(f)); + } + }, new F, Digit>() { + public Digit f(final Three three) { + return new Three(m, three.values().map(f)); + } + }, new F, Digit>() { + public Digit f(final Four four) { + return new Four(m, four.values().map(f)); + } + }); + } + + /** + * Structural pattern matching on digits. Applies the function that matches the structure of this digit. + * + * @param one A function to apply to this digit if it's One. + * @param two A function to apply to this digit if it's Two. + * @param three A function to apply to this digit if it's Three. + * @param four A function to apply to this digit if it's Four. + * @return The result of applying the function matching this Digit. + */ + public abstract B match(final F, B> one, final F, B> two, final F, B> three, + final F, B> four); + + private final Measured m; + + Digit(final Measured m) { + this.m = m; + } + + /** + * Returns the sum of the measurements of this digit according to the monoid. + * + * @return the sum of the measurements of this digit according to the monoid. + */ + public final V measure() { + return foldLeft(Function.curry(new F2() { + public V f(final V v, final A a) { + return m.sum(v, m.measure(a)); + } + }), m.zero()); + } + + /** + * Returns the tree representation of this digit. + * @return the tree representation of this digit. + */ + public final FingerTree toTree() { + final MakeTree mk = mkTree(m); + return match(new F, FingerTree>() { + public FingerTree f(final One one) { + return mk.single(one.value()); + } + }, new F, FingerTree>() { + public FingerTree f(final Two two) { + return mk.deep(mk.one(two.values()._1()), new Empty>(m.nodeMeasured()), mk.one(two.values()._2())); + } + }, new F, FingerTree>() { + public FingerTree f(final Three three) { + return mk.deep(mk.two(three.values()._1(), three.values()._2()), new Empty>(m.nodeMeasured()), + mk.one(three.values()._3())); + } + }, new F, FingerTree>() { + public FingerTree f(final Four four) { + return mk.deep(mk.two(four.values()._1(), four.values()._2()), new Empty>(m.nodeMeasured()), + mk.two(four.values()._3(), four.values()._4())); + } + }); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/Empty.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/Empty.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,69 @@ +package fj.data.fingertrees; + +import fj.F; +import fj.P2; +import static fj.Bottom.error; + +/** + * The empty tree. + */ +public final class Empty extends FingerTree { + Empty(final Measured m) { + super(m); + } + + @Override public FingerTree cons(final A a) { + return new Single(measured(), a); + } + + @Override public FingerTree snoc(final A a) { + return cons(a); + } + + @Override public FingerTree append(final FingerTree t) { + return t; + } + + @Override public P2 lookup(final F o, final int i) { + throw error("Lookup of empty tree."); + } + + @Override public B foldRight(final F> aff, final B z) { + return z; + } + + public A reduceRight(final F> aff) { + throw error("Reduction of empty tree"); + } + + @Override public B foldLeft(final F> bff, final B z) { + return z; + } + + @Override public A reduceLeft(final F> aff) { + throw error("Reduction of empty tree"); + } + + @Override public FingerTree map(final F abf, final Measured m) { + return new Empty(m); + } + + /** + * Returns zero. + * + * @return Zero. + */ + public V measure() { + return measured().zero(); + } + + /** + * Pattern matching on the structure of this tree. Matches the empty tree. + */ + @Override public B match( + final F, B> empty, final F, B> single, final F, B> deep) { + return empty.f(this); + } + + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/FingerTree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/FingerTree.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,162 @@ +package fj.data.fingertrees; + +import fj.*; +import fj.data.Seq; + +/** + * Provides 2-3 finger trees, a functional representation of persistent sequences supporting access to the ends in + * amortized O(1) time. Concatenation and splitting time is O(log n) in the size of the smaller piece. + * A general purpose data structure that can serve as a sequence, priority queue, search tree, priority search queue + * and more. + *

+ * This class serves as a datastructure construction kit, rather than a datastructure in its own right. By supplying + * a monoid, a measurement function, insertion, deletion, and so forth, any purely functional datastructure can be + * emulated. See {@link Seq} for an example. + *

+ * Based on "Finger trees: a simple general-purpose data structure", by Ralf Hinze and Ross Paterson. + * + * @param The monoidal type with which to annotate nodes. + * @param The type of the tree's elements. + */ +public abstract class FingerTree { + private final Measured m; + + /** + * Folds the tree to the right with the given function and the given initial element. + * + * @param f A function with which to fold the tree. + * @param z An initial element to apply to the fold. + * @return A reduction of this tree by applying the given function, associating to the right. + */ + public abstract B foldRight(final F> f, final B z); + + public B foldRight(final F2 f, final B z) { + return foldRight(F2Functions.curry(f), z); + } + + /** + * Folds the tree to the right with the given function. + * + * @param f A function with which to fold the tree. + * @return A reduction of this tree by applying the given function, associating to the right. + */ + public abstract A reduceRight(final F> f); + + /** + * Folds the tree to the left with the given function and the given initial element. + * + * @param f A function with which to fold the tree. + * @param z An initial element to apply to the fold. + * @return A reduction of this tree by applying the given function, associating to the left. + */ + public abstract B foldLeft(final F> f, final B z); + + public B foldLeft(final F2 f, final B z) { + return foldLeft(F2Functions.curry(f), z); + } + + /** + * Folds the tree to the left with the given function. + * + * @param f A function with which to fold the tree. + * @return A reduction of this tree by applying the given function, associating to the right. + */ + public abstract A reduceLeft(final F> f); + + /** + * Maps the given function across this tree, measuring with the given Measured instance. + * + * @param f A function to map across the values of this tree. + * @param m A measuring with which to annotate the tree. + * @return A new tree with the same structure as this tree, with each element transformed by the given function, + * and nodes annotated according to the given measuring. + */ + public abstract FingerTree map(final F f, final Measured m); + + public FingerTree filter(final F f) { + FingerTree tree = new Empty(m); + return foldLeft((acc, a) -> f.f(a) ? acc.snoc(a) : acc, tree); + } + + /** + * Returns the sum of this tree's annotations. + * + * @return the sum of this tree's annotations. + */ + public abstract V measure(); + + /** + * Indicates whether this tree is empty. + * + * @return true if this tree is the empty tree, otherwise false. + */ + public final boolean isEmpty() { + return this instanceof Empty; + } + + Measured measured() { + return m; + } + + /** + * Provides pattern matching on trees. This is the Church encoding of the FingerTree datatype. + * + * @param empty The function to apply to this empty tree. + * @param single A function to apply if this tree contains a single element. + * @param deep A function to apply if this tree contains more than one element. + * @return The result of the function that matches this tree structurally, applied to this tree. + */ + public abstract B match(final F, B> empty, final F, B> single, + final F, B> deep); + + FingerTree(final Measured m) { + this.m = m; + } + + /** + * Constructs a Measured instance for the element type, given a monoid and a measuring function. + * + * @param monoid A monoid for the measures. + * @param measure A function with which to measure element values. + * @return A Measured instance for the given element type, that uses the given monoid and measuring function. + */ + public static Measured measured(final Monoid monoid, final F measure) { + return Measured.measured(monoid, measure); + } + + /** + * Returns a builder of trees and tree components that annotates them using the given Measured instance. + * + * @param m A Measured instance with which to annotate trees, digits, and nodes. + * @return A builder of trees and tree components that annotates them using the given Measured instance. + */ + public static MakeTree mkTree(final Measured m) { + return new MakeTree(m); + } + + /** + * Adds the given element to this tree as the first element. + * + * @param a The element to add to the front of this tree. + * @return A new tree with the given element at the front. + */ + public abstract FingerTree cons(final A a); + + /** + * Adds the given element to this tree as the last element. + * + * @param a The element to add to the end of this tree. + * @return A new tree with the given element at the end. + */ + public abstract FingerTree snoc(final A a); + + /** + * Appends one finger tree to another. + * + * @param t A finger tree to append to this one. + * @return A new finger tree which is a concatenation of this tree and the given tree. + */ + public abstract FingerTree append(final FingerTree t); + + public abstract P2 lookup(final F o, final int i); +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/Four.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/Four.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,39 @@ +package fj.data.fingertrees; + +import fj.data.vector.V4; +import fj.F; + +/** + * A four-element prefix or suffix of a finger tree. + */ +public final class Four extends Digit { + private final V4 as; + + Four(final Measured m, final V4 as) { + super(m); + this.as = as; + } + + public B foldRight(final F> aff, final B z) { + return aff.f(as._1()).f(aff.f(as._2()).f(aff.f(as._3()).f(aff.f(as._4()).f(z)))); + } + + public B foldLeft(final F> bff, final B z) { + return as.toStream().foldLeft(bff, z); + } + + @Override public B match( + final F, B> one, final F, B> two, final F, B> three, + final F, B> four) { + return four.f(this); + } + + /** + * Returns the elements of this digit as a vector. + * + * @return the elements of this digit as a vector. + */ + public V4 values() { + return as; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/MakeTree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/MakeTree.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,162 @@ +package fj.data.fingertrees; + +import fj.data.vector.V2; +import fj.data.vector.V3; + +import static fj.data.vector.V.v; + +/** + * A builder of trees and tree components, supplied with a particular monoid and measuring function. + */ +public final class MakeTree { + private final Measured m; + private final Empty empty; + + MakeTree(final Measured m) { + this.m = m; + this.empty = new Empty(m); + } + + // Tree constructors + + /** + * Constructs an empty tree. + * + * @return The empty tree. + */ + public FingerTree empty() { + return empty; + } + + /** + * Constructs a singleton tree. + * + * @param a A single element for the tree. + * @return A tree with the given value as the single element. + */ + public FingerTree single(final A a) { + return new Single(m, a); + } + + /** + * Constructs a deep tree. This structure consists of two digits, of 1 to 4 elements each, on the left and right, + * with the rest of the tree in the middle. + * + * @param prefix The leftmost elements of the tree. + * @param middle The subtree, which is a Finger Tree of 2-3 nodes. + * @param suffix The rightmost elements of the tree. + * @return A new finger tree with the given prefix, suffix, and middle. + */ + public FingerTree deep(final Digit prefix, final FingerTree> middle, + final Digit suffix) { + return deep(m.sum(prefix.measure(), m.sum(middle.measure(), suffix.measure())), prefix, middle, suffix); + } + + /** + * Constructs a deep tree with the given annotation value. + * + * @param v The value with which to annotate this tree. + * @param prefix The leftmost elements of the tree. + * @param middle The subtree, which is a Finger Tree of 2-3 nodes. + * @param suffix The rightmost elements of the tree. + * @return A new finger tree with the given prefix, suffix, and middle, and annotated with the given value. + */ + public FingerTree deep(final V v, final Digit prefix, final FingerTree> middle, + final Digit suffix) { + return new Deep(m, v, prefix, middle, suffix); + } + + // Digit constructors + + /** + * A digit of one element. + * + * @param a The element of the digit. + * @return A digit of the given element. + */ + public One one(final A a) { + return new One(m, a); + } + + /** + * A digit of two elements. + * + * @param a The first element of the digit. + * @param b The second element of the digit. + * @return A digit of the given elements. + */ + public Two two(final A a, final A b) { + return new Two(m, v(a, b)); + } + + /** + * A digit of three elements. + * + * @param a The first element of the digit. + * @param b The second element of the digit. + * @param c The third element of the digit. + * @return A digit of the given elements. + */ + public Three three(final A a, final A b, final A c) { + return new Three(m, v(a, b, c)); + } + + /** + * A digit of four elements. + * + * @param a The first element of the digit. + * @param b The second element of the digit. + * @param c The third element of the digit. + * @param d The fifth element of the digit. + * @return A digit of the given elements. + */ + public Four four(final A a, final A b, final A c, final A d) { + return new Four(m, v(a, b, c, d)); + } + + // Node constructors + + /** + * A binary tree node. + * + * @param a The left child of the node. + * @param b The right child of the node. + * @return A new binary tree node. + */ + public Node2 node2(final A a, final A b) { + return new Node2(m, v(a, b)); + } + + /** + * A trinary tree node. + * + * @param a The left child of the node. + * @param b The middle child of the node. + * @param c The right child of the node. + * @return A new trinary tree node. + */ + public Node3 node3(final A a, final A b, final A c) { + return new Node3(m, v(a, b, c)); + } + + /** + * A binary tree node + * + * @param v A vector of the node's elements. + * @return A new binary tree node. + */ + public Node2 node2(final V2 v) { + return new Node2(m, v); + } + + /** + * A trinary tree node + * + * @param v A vector of the node's elements. + * @return A new trinary tree node. + */ + public Node3 node3(final V3 v) { + return new Node3(m, v); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/Measured.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/Measured.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,97 @@ +package fj.data.fingertrees; + +import fj.Monoid; +import fj.F; + +/** + * Determines how the elements of a tree are measured and how measures are summed. Consists of a monoid and a + * measuring function. Different instances of this class will result in different behaviours for the tree. + */ +public final class Measured { + private final Monoid m; + private final F measure; + + private Measured(final Monoid m, final F measure) { + this.m = m; + this.measure = measure; + } + + public static Measured measured(final Monoid m, final F measure) { + return new Measured(m, measure); + } + + /** + * Returns the monoid used to sum measures. + * + * @return the monoid used to sum measures. + */ + public Monoid monoid() { + return m; + } + + /** + * Returns the measuring function. + * + * @return the measuring function. + */ + public F measure() { + return measure; + } + + /** + * Measures a given element. + * + * @param a An element to measure. + * @return the element's measurement. + */ + public V measure(final A a) { + return measure.f(a); + } + + /** + * Sums the given measurements with the monoid. + * + * @param a A measurement to add to another. + * @param b A measurement to add to another. + * @return The sum of the two measurements. + */ + public V sum(final V a, final V b) { + return m.sum(a, b); + } + + /** + * Returns the identity measurement for the monoid. + * + * @return the identity measurement for the monoid. + */ + public V zero() { + return m.zero(); + } + + /** + * A measured instance for nodes. + * + * @return A measured instance for nodes. + */ + public Measured> nodeMeasured() { + return new Measured>(m, new F, V>() { + public V f(final Node node) { + return node.measure(); + } + }); + } + + /** + * A measured instance for digits. + * + * @return A measured instance for digits. + */ + public Measured> digitMeasured() { + return new Measured>(m, new F, V>() { + public V f(final Digit d) { + return d.measure(); + } + }); + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/Node.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/Node.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,69 @@ +package fj.data.fingertrees; + +import fj.F; +import fj.F2; +import fj.P2; +import static fj.Function.curry; + +/** + * An inner node of the 2-3 tree. + */ +public abstract class Node { + private final Measured m; + private final V measure; + + public abstract B foldRight(final F> f, final B z); + + public abstract B foldLeft(final F> f, final B z); + + public static F, B>> foldLeft_(final F> bff) { + return curry(new F2, B>() { + public B f(final B b, final Node node) { return node.foldLeft(bff, b); } + }); + } + + public static F, B>> foldRight_(final F> aff) { + return curry(new F2, B>() { + public B f(final B b, final Node node) { return node.foldRight(aff, b); } + }); + } + + public final Node map(final F f, final Measured m) { + return match(new F, Node>() { + public Node f(final Node2 node2) { + return new Node2(m, node2.toVector().map(f)); + } + }, new F, Node>() { + public Node f(final Node3 node3) { + return new Node3(m, node3.toVector().map(f)); + } + }); + } + + public static F, Node> liftM(final F f, final Measured m) { + return new F, Node>() { + public Node f(final Node node) { + return node.map(f, m); + } + }; + } + + public abstract Digit toDigit(); + + Node(final Measured m, final V measure) { + this.m = m; + this.measure = measure; + } + + public final V measure() { + return measure; + } + + Measured measured() { + return m; + } + + public abstract P2 lookup(final F o, final int i); + + public abstract B match(final F, B> n2, final F, B> n3); +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/Node2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/Node2.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,42 @@ +package fj.data.fingertrees; + +import fj.data.vector.V2; +import fj.F; +import fj.P2; + +/** + * A two-element inner tree node. + */ +public final class Node2 extends Node { + private final V2 as; + + Node2(final Measured m, final V2 as) { + super(m, m.sum(m.measure(as._1()), m.measure(as._2()))); + this.as = as; + } + + @Override public B foldRight(final F> aff, final B z) { + return aff.f(as._1()).f(aff.f(as._2()).f(z)); + } + + @Override public B foldLeft(final F> bff, final B z) { + return bff.f(bff.f(z).f(as._1())).f(as._2()); + } + + public Digit toDigit() { + return new Two(measured(), as); + } + + @SuppressWarnings({"ReturnOfNull"}) + @Override public P2 lookup(final F o, final int i) { + return null; // TODO + } + + public B match(final F, B> n2, final F, B> n3) { + return n2.f(this); + } + + public V2 toVector() { + return as; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/Node3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/Node3.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,42 @@ +package fj.data.fingertrees; + +import fj.data.vector.V3; +import fj.F; +import fj.P2; + +/** + * A three-element inner tree node. + */ +public final class Node3 extends Node { + private final V3 as; + + Node3(final Measured m, final V3 as) { + super(m, m.sum(m.measure(as._1()), m.sum(m.measure(as._2()), m.measure(as._3())))); + this.as = as; + } + + public B foldRight(final F> aff, final B z) { + return aff.f(as._1()).f(aff.f(as._2()).f(aff.f(as._3()).f(z))); + } + + public B foldLeft(final F> bff, final B z) { + return bff.f(bff.f(bff.f(z).f(as._1())).f(as._2())).f(as._3()); + } + + public B match(final F, B> n2, final F, B> n3) { + return n3.f(this); + } + + public Digit toDigit() { + return new Three(measured(), as); + } + + @SuppressWarnings({"ReturnOfNull"}) + public P2 lookup(final F o, final int i) { + return null; //TODO + } + + public V3 toVector() { + return as; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/One.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/One.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,38 @@ +package fj.data.fingertrees; + +import fj.F; + +/** + * A single-element prefix or suffix of a finger tree. + */ +public final class One extends Digit { + private final A a; + + One(final Measured m, final A a) { + super(m); + this.a = a; + } + + public B foldRight(final F> aff, final B z) { + return aff.f(a).f(z); + } + + public B foldLeft(final F> bff, final B z) { + return bff.f(z).f(a); + } + + @Override public B match( + final F, B> one, final F, B> two, final F, B> three, + final F, B> four) { + return one.f(this); + } + + /** + * Returns the single element in this digit. + * + * @return the single element in this digit. + */ + public A value() { + return a; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/Single.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/Single.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,83 @@ +package fj.data.fingertrees; + +import fj.F; +import fj.P2; +import static fj.P.p; + +/** + * A tree with a single element. + */ +public final class Single extends FingerTree { + private final A a; + private final V v; + + Single(final Measured m, final A a) { + super(m); + this.a = a; + v = m.measure(a); + } + + @Override public B foldRight(final F> aff, final B z) { + return aff.f(a).f(z); + } + + @Override public A reduceRight(final F> aff) { + return a; + } + + @Override public B foldLeft(final F> bff, final B z) { + return bff.f(z).f(a); + } + + @Override public A reduceLeft(final F> aff) { + return a; + } + + @Override public FingerTree map(final F abf, final Measured m) { + return new Single(m, abf.f(a)); + } + + /** + * Returns the annotation of this tree's single element. + * + * @return the annotation of this tree's single element. + */ + public V measure() { + return v; + } + + /** + * Pattern matching on the structure of this tree. Matches the singleton tree. + */ + @Override public B match(final F, B> empty, final F, B> single, + final F, B> deep) { + return single.f(this); + } + + @Override public FingerTree cons(final A b) { + final MakeTree mk = mkTree(measured()); + return mk.deep(mk.one(b), new Empty>(measured().nodeMeasured()), mk.one(a)); + } + + @Override public FingerTree snoc(final A b) { + final MakeTree mk = mkTree(measured()); + return mk.deep(mk.one(a), new Empty>(measured().nodeMeasured()), mk.one(b)); + } + + @Override public FingerTree append(final FingerTree t) { + return t.cons(a); + } + + @Override public P2 lookup(final F o, final int i) { + return p(i, a); + } + + /** + * Returns the single element of this tree. + * + * @return the single element of this tree. + */ + public A value() { + return a; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/Three.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/Three.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,39 @@ +package fj.data.fingertrees; + +import fj.data.vector.V3; +import fj.F; + +/** + * A three-element prefix or suffix of a finger tree. + */ +public final class Three extends Digit { + private final V3 as; + + Three(final Measured m, final V3 as) { + super(m); + this.as = as; + } + + public B foldRight(final F> aff, final B z) { + return aff.f(as._1()).f(aff.f(as._2()).f(aff.f(as._3()).f(z))); + } + + public B foldLeft(final F> bff, final B z) { + return as.toStream().foldLeft(bff, z); + } + + @Override public B match( + final F, B> one, final F, B> two, final F, B> three, + final F, B> four) { + return three.f(this); + } + + /** + * Returns the elements of this digit as a vector. + * + * @return the elements of this digit as a vector. + */ + public V3 values() { + return as; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/Two.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/Two.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,39 @@ +package fj.data.fingertrees; + +import fj.data.vector.V2; +import fj.F; + +/** + * A two-element prefix or suffix of a finger tree. + */ +public final class Two extends Digit { + private final V2 as; + + Two(final Measured m, final V2 as) { + super(m); + this.as = as; + } + + public B foldRight(final F> aff, final B z) { + return aff.f(as._1()).f(aff.f(as._2()).f(z)); + } + + public B foldLeft(final F> bff, final B z) { + return as.toStream().foldLeft(bff, z); + } + + @Override public B match( + final F, B> one, final F, B> two, final F, B> three, + final F, B> four) { + return two.f(this); + } + + /** + * Returns the elements of this digit as a vector. + * + * @return the elements of this digit as a vector. + */ + public V2 values() { + return as; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/fingertrees/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/fingertrees/package-info.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,11 @@ +/** + * Provides 2-3 finger trees, a functional representation of persistent sequences supporting access to the ends in + * amortized O(1) time. Concatenation and splitting time is O(log n) in the size of the smaller piece. + * A general purpose data structure that can serve as a sequence, priority queue, search tree, priority search queue + * and more. + + * Based on "Finger trees: a simple general-purpose data structure", by Ralf Hinze and Ross Paterson. + * + * @version %build.number% + */ +package fj.data.fingertrees; diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/hlist/HList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/hlist/HList.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,316 @@ +package fj.data.hlist; + +import fj.F; +import fj.F2; +import fj.F3; +import fj.P; +import fj.P2; +import fj.Unit; +import static fj.Function.compose; + +/** + * Type-safe heterogeneous lists. + * + * @param The specific type of the list, as a subtype of HList + */ +public abstract class HList> { + + HList() { + } + + /** + * Extends (cons) this list by prepending the given element, returning a new list. + * + * @param e an element to prepend to this list. + * @return a new heterogeneous list, consisting of the given element prepended to this list. + */ + public abstract HCons extend(E e); + + public abstract Apply, HCons> extender(); + + private static final HNil nil = new HNil(); + + /** + * Returns the empty list. + * + * @return the empty list. + */ + public static HNil nil() { + return nil; + } + + /** + * Returns a heterogeneous list consisting of an element and another list. + * + * @param e an element to put in a list. + * @param l the rest of the list. + * @return a heterogeneous list consisting of an element and another list. + */ + public static > HCons cons(final E e, final L l) { + return new HCons(e, l); + } + + /** + * Returns a heterogeneous list consisting of a single element. + * + * @param e an element to put in a list + * @return a heterogeneous list consisting of a single element. + */ + public static HCons single(final E e) { + return cons(e, nil()); + } + + /** + * The concatenation of two heterogeneous lists. + * + * @param The type of the first list. + * @param The type of the second list. + * @param The type of the combined list. + */ + public static final class HAppend { + private final F2 append; + + private HAppend(final F2 f) { + append = f; + } + + /** + * Append a given heterogeneous list to another. + * + * @param a a heterogeneous list to be appended to. + * @param b a heterogeneous list to append to another. + * @return a new heterogeneous list consisting of the second argument appended to the first. + */ + public C append(final A a, final B b) { + return append.f(a, b); + } + + /** + * Returns a method for concatenating lists to the empty list. + * + * @return a method for concatenating lists to the empty list. + */ + public static > HAppend append() { + return new HAppend(new F2() { + public L f(final HNil hNil, final L l) { + return l; + } + }); + } + + /** + * Returns a method for appending lists to a nonempty heterogeneous list. + * + * @param h a method for appending lists to the tail of the given nonempty list. + * @return a method for appending lists to a nonempty heterogeneous list. + */ + public static , B, C extends HList, H extends HAppend> + HAppend, B, HCons> append(final H h) { + return new HAppend, B, HCons>(new F2, B, HCons>() { + public HCons f(final HCons c, final B l) { + return cons(c.head(), h.append(c.tail(), l)); + } + }); + } + } + + /** + * Type-level function application operators. + * + * @param The type of the function to apply. + * @param The domain of the function. + * @param The function's codomain. + */ + public abstract static class Apply { + public abstract R apply(F$ f, A a); + + /** + * Function application operator. + * + * @return an operator that applies a given function to a given argument. + */ + public static Apply, X, Y> f() { + return new Apply, X, Y>() { + public Y apply(final F f, final X x) { + return f.f(x); + } + }; + } + + /** + * Identity operator + * + * @return An operator that returns its second argument no matter which function is being applied. + */ + public static Apply id() { + return new Apply() { + public X apply(final Unit f, final X x) { + return x; + } + }; + } + + /** + * A function application operator for function composition. + * + * @param The domain. + * @param The type through which to compose. + * @param The codomain. + * @return an operator that composes functions. + */ + public static Apply, F>, F> comp() { + return new Apply, F>, F>() { + public F apply(final Unit f, final P2, F> fs) { + return compose(fs._2(), fs._1()); + } + }; + } + + /** + * An operator for the construction of heterogeneous lists. + * + * @return an operator that constructs heterogeneous lists. + */ + public static > Apply, HCons> cons() { + return new Apply, HCons>() { + public HCons apply(final Unit f, final P2 p) { + return HList.cons(p._1(), p._2()); + } + }; + } + + /** + * A function application operator for concatenating heterogeneous lists. + * + * @param The type of the list to which to append. + * @param The type of the list to append. + * @param The type of the concatenated list. + * @return an operator that concatenates heterogeneous lists. + */ + public static Apply, P2, C> append() { + return new Apply, P2, C>() { + public C apply(final HAppend f, final P2 p) { + return f.append(p._1(), p._2()); + } + }; + } + } + + /** + * The catamorphism over heterogeneous lists. + * + * @param The type of the function with which to fold. + * @param The type of the value to be substituted for the empty list. + * @param The type of the heterogeneous list to be folded. + * @param The return type of the fold. + */ + public static final class HFoldr { + + private final F3 foldRight; + + private HFoldr(final F3 foldRight) { + this.foldRight = foldRight; + } + + /** + * A fold instance for the empty list. + * + * @param The type of the function with which to fold. + * @param The type of value that this fold returns. + * @return a fold instance for the empty list. + */ + public static HFoldr hFoldr() { + return new HFoldr(new F3() { + public V f(final G f, final V v, final HNil hNil) { + return v; + } + }); + } + + /** + * A fold instance for a non-empty heterogeneous list + * + * @param p An operator that applies a function on the head of the list and the fold of its tail. + * @param h A fold instance for the tail of the list. + * @param The type of the head of the list. + * @param The type of function to apply to the head of the list and the fold of its tail. + * @param The type of value to substitute for the empty list. + * @param The type of the tail of the list. + * @param The type of the fold of the tail of the list. + * @param The return type of the fold. + * @param The type of the fold instance for the tail of the list. + * @param The type of the given function application operator. + * @return A fold instance for a non-empty heterogeneous list. + */ + public static , R, RR, + H extends HFoldr, + PP extends Apply, RR>> + HFoldr, RR> hFoldr(final PP p, final H h) { + return new HFoldr, RR>(new F3, RR>() { + public RR f(final G f, final V v, final HCons c) { + return p.apply(f, P.p(c.head(), h.foldRight(f, v, c.tail()))); + } + }); + } + + /** + * Folds a non-empty heterogeneous list. + * + * @param f A function with which to fold. + * @param v The value to substitute for the empty list. + * @param l The heterogeneous list to be folded. + * @return a value obtained by folding the given list with the given function. + */ + public R foldRight(final G f, final V v, final L l) { + return foldRight.f(f, v, l); + } + + } + + /** + * The nonempty list + */ + public static final class HCons> extends HList> { + private final E e; + private final L l; + + HCons(final E e, final L l) { + this.e = e; + this.l = l; + } + + public E head() { + return e; + } + + public L tail() { + return l; + } + + public Apply>, HCons>> extender() { + return Apply.cons(); + } + + public HCons> extend(final X e) { + return cons(e, this); + } + + } + + /** + * The empty list + */ + public static final class HNil extends HList { + HNil() { + } + + public HCons extend(final E e) { + return cons(e, this); + } + + public Apply, HCons> extender() { + return Apply.cons(); + } + + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/hlist/HPre.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/hlist/HPre.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,310 @@ +package fj.data.hlist; + +import fj.F; +import fj.Show; + +/** + * A basic prelude of values lifted into the type system. + */ +@SuppressWarnings({"ALL"}) +public final class HPre { + private HPre() { + throw new UnsupportedOperationException(); + } + + /** + * A type-level Boolean + */ + public static class HBool { + private HBool() { + } + } + + /** + * Boolean true + */ + public static class HTrue extends HBool { + private HTrue() { + } + } + + /** + * Boolean false + */ + public static class HFalse extends HBool { + private HFalse() { + } + } + + private static final HTrue hTrue = new HTrue(); + private static final HFalse hFalse = new HFalse(); + + /** + * Returns a boolean value whose type represents truth. + * + * @return a boolean value whose type represents truth. + */ + public static HTrue hTrue() { + return hTrue; + } + + /** + * Returns a boolean value whose type represents falsehood. + * + * @return a boolean value whose type represents falsehood. + */ + public static HFalse hFalse() { + return hFalse; + } + + /** + * Type-level boolean conjunction. A value of this type represents evidence that AB -> C + * + * @param A boolean + * @param A boolean + * @param The logical implication of A and B + */ + public static final class HAnd { + private final C v; + + private HAnd(final C v) { + this.v = v; + } + + public C v() { + return v; + } + + public static HAnd hAnd(final HFalse a, final HFalse b) { + return new HAnd(hFalse()); + } + + public static HAnd hAnd(final HTrue a, final HFalse b) { + return new HAnd(hFalse()); + } + + public static HAnd hAnd(final HFalse a, final HTrue b) { + return new HAnd(hFalse()); + } + + public static HAnd hAnd(final HTrue a, final HTrue b) { + return new HAnd(hTrue()); + } + } + + /** + * Type-level boolean disjunction. A value of this type represents evidence that A+B -> C + * + * @param A boolean + * @param A boolean + * @param The logical implication of A or B + */ + public static final class HOr { + private final C v; + + private HOr(final C v) { + this.v = v; + } + + public C v() { + return v; + } + + public static HOr hOr(final HFalse a, final HFalse b) { + return new HOr(hFalse()); + } + + public static HOr hOr(final HTrue a, final HFalse b) { + return new HOr(hTrue()); + } + + public static HOr hOr(final HFalse a, final HTrue b) { + return new HOr(hTrue()); + } + + public static HOr hOr(final HTrue a, final HTrue b) { + return new HOr(hTrue()); + } + } + + /** + * A type-level conditional. The type of the last parameter is implied by the first three. + * + * @param A boolean + * @param The type of Z if T is true. + * @param The type of Z if T is false. + * @param A type that is either X or Z, depending on T. + */ + public static final class HCond { + private HCond(final Z z) { + this.z = z; + } + + private final Z z; + + public Z v() { + return z; + } + + public static HCond hCond(final HFalse t, final X x, final Y y) { + return new HCond(y); + } + + public static HCond hCond(final HTrue t, final X x, final Y y) { + return new HCond(x); + } + } + + /** + * Type-level natural numbers. + */ + public abstract static class HNat> { + public abstract Show show(); + + public abstract Integer toInteger(); + + public static HZero hZero() { + return new HZero(); + } + + public static > HSucc hSucc(final N n) { + return new HSucc(n); + } + + public static > N hPred(final HSucc n) { + return n.pred; + } + } + + /** + * Type-level zero + */ + public static final class HZero extends HNat { + private HZero() { + } + + public Show show() { + return Show.showS(new F() { + public String f(final HZero hZero) { + return "HZero"; + } + }); + } + + public Integer toInteger() { + return 0; + } + } + + /** + * A natural number N + 1 + * + * @param The predecessor of this number. + */ + public static final class HSucc> extends HNat> { + private HSucc(final N n) { + pred = n; + } + + private final N pred; + + public Show> show() { + return Show.showS(new F, String>() { + public String f(final HSucc s) { + return "HSucc (" + s.show().showS(s) + ')'; + } + }); + } + + public Integer toInteger() { + return 1 + pred.toInteger(); + } + } + + /** + * Type-level equality. Represents evidence for X and Y being equal, or counterevidence against. + */ + public static final class HEq { + private final B v; + + private HEq(final B v) { + this.v = v; + } + + public B v() { + return v; + } + + /** + * Zero is equal to itself. + * + * @param a Zero + * @param b Zero + * @return Equality for Zero + */ + public static HEq eq(final HZero a, final HZero b) { + return new HEq(hTrue()); + } + + /** + * Zero is not equal to anything other than zero. + */ + public static > HEq, HFalse> eq(final HZero a, final HSucc b) { + return new HEq, HFalse>(hFalse()); + } + + /** + * Zero is not equal to anything other than zero. + */ + public static > HEq, HZero, HFalse> eq(final HSucc a, final HZero b) { + return new HEq, HZero, HFalse>(hFalse()); + } + + /** + * A number is equal to another if their predecessors are equal. + */ + public static , NN extends HNat, B extends HBool, E extends HEq> + HEq, HSucc, B> eq(final HSucc a, final HSucc b, final E e) { + return new HEq, HSucc, B>(e.v()); + } + + } + + /** + * Type-level integer arithmetic + */ + public static final class HAdd, B extends HNat, C extends HNat> { + private final C sum; + + private HAdd(final C sum) { + this.sum = sum; + } + + public C sum() { + return this.sum; + } + + /** + * The sum of zero and any other number is that number. + */ + public static > HAdd, HSucc> add(final HZero a, final HSucc b) { + return new HAdd, HSucc>(b); + } + + /** + * The sum of zero and any other number is that number. + */ + public static > HAdd, HZero, HSucc> add(final HSucc a, final HZero b) { + return new HAdd, HZero, HSucc>(a); + } + + /** + * The sum of numbers a and b is one greater than the sum of b and the predecessor of a. + */ + public static , M extends HNat, R extends HNat, H extends HAdd, R>> + HAdd, HSucc, HSucc> add(final HSucc a, final HSucc b, final H h) { + return new HAdd, HSucc, HSucc>(HNat.hSucc(h.sum())); + } + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/hlist/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/hlist/package-info.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,6 @@ +/** + * Type-safe, extensible, heterogeneous lists + * + * @version %build.number% + */ +package fj.data.hlist; diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/package-info.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,6 @@ +/** + * Common algebraic data types. + * + * @version %build.number% + */ +package fj.data; diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/vector/V.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/vector/V.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,180 @@ +package fj.data.vector; + +import fj.F2; +import fj.F3; +import fj.F4; +import fj.F5; +import fj.P; +import fj.P1; +import fj.P2; + +/** + * Functions across vectors. + */ +public final class V { + + private V() { + } + + /** + * Puts elements in a vector-2. + * + * @param a1 An element to put in a vector. + * @param a2 An element to put in a vector. + * @return The vector-2. + */ + public static V2 v(final A a1, final A a2) { + return V2.p(P.p(a1, a2)); + } + + /** + * Puts elements in a vector-2. + * + * @param a1 An element to put in a vector. + * @param a2 An element to put in a vector. + * @return The vector-2. + */ + public static V2 v(final P1 a1, final P1 a2) { + return V2.p(new P2() { + public A _1() { + return a1._1(); + } + + public A _2() { + return a2._1(); + } + }); + } + + /** + * Returns a function that puts elements in a vector-2. + * + * @return A function that puts elements in a vector-2. + */ + public static F2> v2() { + return new F2>() { + public V2 f(final A a, final A a1) { + return v(a, a1); + } + }; + } + + /** + * Puts elements in a vector-3. + * + * @param a1 An element to put in a vector. + * @param a2 An element to put in a vector. + * @param a3 An element to put in a vector. + * @return The vector-3. + */ + public static V3 v(final A a1, final A a2, final A a3) { + return V3.p(P.p(a1, a2, a3)); + } + + /** + * Puts elements in a vector-3. + * + * @param a1 An element to put in a vector. + * @param a2 An element to put in a vector. + * @param a3 An element to put in a vector. + * @return The vector-3. + */ + public static V3 v(final P1 a1, final P1 a2, final P1 a3) { + return V3.cons(a1, v(a2, a3)); + } + + /** + * Returns a function that puts elements in a vector-3. + * + * @return A function that puts elements in a vector-3. + */ + public static F3> v3() { + return new F3>() { + public V3 f(final A a, final A a1, final A a2) { + return v(a, a1, a2); + } + }; + } + + /** + * Puts elements in a vector-4. + * + * @param a1 An element to put in a vector. + * @param a2 An element to put in a vector. + * @param a3 An element to put in a vector. + * @param a4 An element to put in a vector. + * @return The vector-4. + */ + public static V4 v(final A a1, final A a2, final A a3, final A a4) { + return V4.p(P.p(a1, a2, a3, a4)); + } + + /** + * Puts elements in a vector-4. + * + * @param a1 An element to put in a vector. + * @param a2 An element to put in a vector. + * @param a3 An element to put in a vector. + * @param a4 An element to put in a vector. + * @return The vector-4. + */ + public static V4 v(final P1 a1, final P1 a2, final P1 a3, final P1 a4) { + return V4.cons(a1, v(a2, a3, a4)); + } + + /** + * Returns a function that puts elements in a vector-4. + * + * @return A function that puts elements in a vector-4. + */ + public static F4> v4() { + return new F4>() { + public V4 f(final A a, final A a1, final A a2, final A a3) { + return v(a, a1, a2, a3); + } + }; + } + + + /** + * Puts elements in a vector-5. + * + * @param a1 An element to put in a vector. + * @param a2 An element to put in a vector. + * @param a3 An element to put in a vector. + * @param a4 An element to put in a vector. + * @param a5 An element to put in a vector. + * @return The vector-5. + */ + public static V5 v(final A a1, final A a2, final A a3, final A a4, final A a5) { + return V5.p(P.p(a1, a2, a3, a4, a5)); + } + + /** + * Puts elements in a vector-5. + * + * @param a1 An element to put in a vector. + * @param a2 An element to put in a vector. + * @param a3 An element to put in a vector. + * @param a4 An element to put in a vector. + * @param a5 An element to put in a vector. + * @return The vector-5. + */ + public static V5 v(final P1 a1, final P1 a2, final P1 a3, final P1 a4, final P1 a5) { + return V5.cons(a1, v(a2, a3, a4, a5)); + } + + /** + * Returns a function that puts elements in a vector-5. + * + * @return A function that puts elements in a vector-5. + */ + public static F5> v5() { + return new F5>() { + public V5 f(final A a, final A a1, final A a2, final A a3, final A a4) { + return v(a, a1, a2, a3, a4); + } + }; + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/vector/V2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/vector/V2.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,224 @@ +package fj.data.vector; + +import fj.F; +import fj.F2; +import static fj.Function.curry; +import static fj.P.p2; +import fj.P1; +import fj.P2; +import fj.data.Array; +import fj.data.List; +import fj.data.NonEmptyList; +import fj.data.Stream; + +import java.util.Iterator; + +/** + * A vector-2. + */ +public final class V2 implements Iterable { + + private final P2 inner; + + private V2(final P2 inner) { + this.inner = inner; + } + + /** + * Creates a vector-2 from a homogeneous product-2. + * + * @param p The product-2 from which to create a vector. + * @return A new vector-2. + */ + public static V2 p(final P2 p) { + return new V2(p); + } + + /** + * Returns the first element of this vector. + * + * @return the first element of this vector. + */ + public A _1() { + return inner._1(); + } + + /** + * Returns the second element of this vector. + * + * @return the second element of this vector. + */ + public A _2() { + return inner._2(); + } + + /** + * A first-class function to get the first element of a vector. + * + * @return a function that gets the first element of a given vector. + */ + public static F, A> __1() { + return new F, A>() { + public A f(final V2 v) { + return v._1(); + } + }; + } + + /** + * A first-class function to get the second element of a vector. + * + * @return a function that gets the second element of a given vector. + */ + public static F, A> __2() { + return new F, A>() { + public A f(final V2 v) { + return v._2(); + } + }; + } + + /** + * Returns an iterator for the elements of this vector. + * + * @return an iterator for the elements of this vector. + */ + public Iterator iterator() { + return toStream().iterator(); + } + + /** + * Returns a homogeneous product-2 equivalent to this vector. + * + * @return a homogeneous product-2 equivalent to this vector. + */ + public P2 p() { + return inner; + } + + /** + * Returns a nonempty list with the elements of this vector. + * + * @return a nonempty list with the elements of this vector. + */ + public NonEmptyList toNonEmptyList() { + return NonEmptyList.nel(_1(), List.single(_2())); + } + + /** + * Returns a stream of the elements of this vector. + * + * @return a stream of the elements of this vector. + */ + public Stream toStream() { + return Stream.cons(_1(), new P1>() { + public Stream _1() { + return Stream.single(_2()); + } + }); + } + + /** + * Returns a function that transforms a vector-2 to a stream of its elements. + * + * @return a function that transforms a vector-2 to a stream of its elements. + */ + public static F, Stream> toStream_() { + return new F, Stream>() { + public Stream f(final V2 v) { + return v.toStream(); + } + }; + } + + /** + * Returns a function that transforms a vector-2 to the equivalent product-2. + * + * @return a function that transforms a vector-2 to the equivalent product-2. + */ + public static F, P2> p_() { + return new F, P2>() { + public P2 f(final V2 v) { + return v.p(); + } + }; + } + + /** + * Returns an array with the elements of this vector. + * + * @return an array with the elements of this vector. + */ + @SuppressWarnings("unchecked") + public Array toArray() { + return Array.array(_1(), _2()); + } + + /** + * Maps the given function across this vector. + * + * @param f The function to map across this vector. + * @return A new vector after the given function has been applied to each element. + */ + public V2 map(final F f) { + return p(inner.split(f, f)); + } + + /** + * Performs function application within a vector (applicative functor pattern). + * + * @param vf The vector of functions to apply. + * @return A new vector after zipping the given vector of functions over this vector. + */ + public V2 apply(final V2> vf) { + return p(inner.split(vf._1(), vf._2())); + } + + /** + * Zips this vector with the given vector using the given function to produce a new vector. + * + * @param bs The vector to zip this vector with. + * @param f The function to zip this vector and the given vector with. + * @return A new vector with the results of the function. + */ + public V2 zipWith(final F> f, final V2 bs) { + return bs.apply(map(f)); + } + + /** + * Zips this vector with the given vector to produce a vector of pairs. + * + * @param bs The vector to zip this vector with. + * @return A new vector with a length the same as the shortest of this vector and the given + * vector. + */ + public V2> zip(final V2 bs) { + final F>> __2 = p2(); + return zipWith(__2, bs); + } + + /** + * Zips this vector with the given vector to produce a vector of vectors. + * + * @param bs The vector to zip this vector with. + * @return A new vector of vectors. + */ + public V2> vzip(final V2 bs) { + final F2> __2 = V.v2(); + return zipWith(curry(__2), bs); + } + + /** + * Return the first element of this vector as a product-1. + * + * @return the first element of this vector as a product-1. + */ + public P1 head() { + return new P1() { + public A _1() { + return V2.this._1(); + } + }; + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/vector/V3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/vector/V3.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,289 @@ +package fj.data.vector; + +import fj.F; +import fj.F2; +import fj.P1; +import fj.P2; +import fj.P3; +import static fj.Function.curry; +import static fj.P.p2; +import fj.data.Array; +import fj.data.NonEmptyList; +import fj.data.Stream; + +import java.util.Iterator; + +/** + * A vector-3. + */ +public final class V3 implements Iterable { + + private final V2 tail; + private final P1 head; + + private V3(final P1 head, final V2 tail) { + this.head = head; + this.tail = tail; + } + + /** + * Creates a vector-3 from a homogeneous product-3. + * + * @param p The product-3 from which to create a vector. + * @return A new vector-3. + */ + public static V3 p(final P3 p) { + return new V3(new P1() { + public A _1() { + return p._1(); + } + }, V2.p(new P2() { + public A _1() { + return p._2(); + } + + public A _2() { + return p._3(); + } + })); + } + + /** + * Creates a vector-3 from a head and a tail. + * + * @param head The value to put as the first element of the vector. + * @param tail The vector representing all but the first element of the new vector. + * @return The new vector. + */ + public static V3 cons(final P1 head, final V2 tail) { + return new V3(head, tail); + } + + /** + * Returns the first element of this vector. + * + * @return the first element of this vector. + */ + public A _1() { + return head._1(); + } + + /** + * Returns the second element of this vector. + * + * @return the second element of this vector. + */ + public A _2() { + return tail._1(); + } + + /** + * Returns the third element of this vector. + * + * @return the third element of this vector. + */ + public A _3() { + return tail._2(); + } + + /** + * Returns all but the first element of this vector, as a vector-2. + * + * @return all but the first element of this vector, as a vector-2. + */ + public V2 tail() { + return tail; + } + + /** + * Returns the first element of this vector, as a product-1. + * + * @return the first element of this vector, as a product-1. + */ + public P1 head() { + return head; + } + + /** + * Returns a homogeneous product-3 equivalent to this vector. + * + * @return a homogeneous product-3 equivalent to this vector. + */ + public P3 p() { + return new P3() { + public A _1() { + return V3.this._1(); + } + + public A _2() { + return V3.this._2(); + } + + public A _3() { + return V3.this._3(); + } + }; + } + + /** + * Returns an array with the elements of this vector. + * + * @return an array with the elements of this vector. + */ + @SuppressWarnings("unchecked") + public Array toArray() { + return Array.array(_1(), _2(), _3()); + } + + + /** + * Performs function application within a vector (applicative functor pattern). + * + * @param vf The vector of functions to apply. + * @return A new vector after zipping the given vector of functions over this vector. + */ + public V3 apply(final V3> vf) { + return new V3(head.apply(vf.head()), tail.apply(vf.tail())); + } + + /** + * Zips this vector with the given vector using the given function to produce a new vector. + * + * @param bs The vector to zip this vector with. + * @param f The function to zip this vector and the given vector with. + * @return A new vector with the results of the function. + */ + public V3 zipWith(final F> f, final V3 bs) { + return bs.apply(map(f)); + } + + /** + * Zips this vector with the given vector to produce a vector of pairs. + * + * @param bs The vector to zip this vector with. + * @return A new vector with a length the same as the shortest of this vector and the given + * vector. + */ + public V3> zip(final V3 bs) { + final F>> __2 = p2(); + return zipWith(__2, bs); + } + + /** + * Zips this vector with the given vector to produce a vector of vectors. + * + * @param bs The vector to zip this vector with. + * @return A new vector of vectors. + */ + public V3> vzip(final V3 bs) { + final F2> __2 = V.v2(); + return zipWith(curry(__2), bs); + } + + /** + * Returns an iterator for the elements of this vector. + * + * @return an iterator for the elements of this vector. + */ + public Iterator iterator() { + return toStream().iterator(); + } + + /** + * Returns a nonempty list with the elements of this vector. + * + * @return a nonempty list with the elements of this vector. + */ + public NonEmptyList toNonEmptyList() { + return NonEmptyList.nel(head()._1(), tail().toNonEmptyList().toList()); + } + + /** + * Returns a stream of the elements of this vector. + * + * @return a stream of the elements of this vector. + */ + public Stream toStream() { + return Stream.cons(head()._1(), new P1>() { + public Stream _1() { + return tail().toStream(); + } + }); + } + + /** + * Maps the given function across this vector. + * + * @param f The function to map across this vector. + * @return A new vector after the given function has been applied to each element. + */ + public V3 map(final F f) { + return new V3(head().map(f), tail().map(f)); + } + + /** + * Returns a function that transforms a vector-3 to a stream of its elements. + * + * @return a function that transforms a vector-3 to a stream of its elements. + */ + public static F, Stream> toStream_() { + return new F, Stream>() { + public Stream f(final V3 v) { + return v.toStream(); + } + }; + } + + /** + * Returns a function that transforms a vector-3 to the equivalent product-3. + * + * @return a function that transforms a vector-3 to the equivalent product-3. + */ + public static F, P3> p_() { + return new F, P3>() { + public P3 f(final V3 v) { + return v.p(); + } + }; + } + + /** + * A first-class function to get the first element of a vector. + * + * @return a function that gets the first element of a given vector. + */ + public static F, A> __1() { + return new F, A>() { + public A f(final V3 v) { + return v._1(); + } + }; + } + + /** + * A first-class function to get the second element of a vector. + * + * @return a function that gets the second element of a given vector. + */ + public static F, A> __2() { + return new F, A>() { + public A f(final V3 v) { + return v._2(); + } + }; + } + + /** + * A first-class function to get the third element of a vector. + * + * @return a function that gets the third element of a given vector. + */ + public static F, A> __3() { + return new F, A>() { + public A f(final V3 v) { + return v._3(); + } + }; + } + +} \ No newline at end of file diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/vector/V4.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/vector/V4.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,318 @@ +package fj.data.vector; + +import fj.F; +import fj.F2; +import fj.P1; +import fj.P2; +import fj.P3; +import fj.P4; +import static fj.Function.curry; +import static fj.P.p2; +import fj.data.Array; +import fj.data.NonEmptyList; +import fj.data.Stream; + +import java.util.Iterator; + +/** + * A vector-4. + */ +public final class V4 implements Iterable { + + private final V3 tail; + private final P1 head; + + private V4(final P1 head, final V3 tail) { + this.head = head; + this.tail = tail; + } + + /** + * Creates a vector-4 from a homogeneous product-4. + * + * @param p The product-4 from which to create a vector. + * @return A new vector-4. + */ + public static V4 p(final P4 p) { + return new V4(new P1() { + public A _1() { + return p._1(); + } + }, V3.p(new P3() { + public A _1() { + return p._2(); + } + + public A _2() { + return p._3(); + } + + public A _3() { + return p._4(); + } + })); + } + + /** + * Creates a vector-4 from a head and a tail. + * + * @param head The value to put as the first element of the vector. + * @param tail The vector representing all but the first element of the new vector. + * @return The new vector. + */ + public static V4 cons(final P1 head, final V3 tail) { + return new V4(head, tail); + } + + /** + * Returns the first element of this vector. + * + * @return the first element of this vector. + */ + public A _1() { + return head._1(); + } + + /** + * Returns the second element of this vector. + * + * @return the second element of this vector. + */ + public A _2() { + return tail._1(); + } + + /** + * Returns the third element of this vector. + * + * @return the third element of this vector. + */ + public A _3() { + return tail._2(); + } + + /** + * Returns the fourth element of this vector. + * + * @return the fourth element of this vector. + */ + public A _4() { + return tail._3(); + } + + /** + * Returns all but the first element of this vector, as a vector-3. + * + * @return all but the first element of this vector, as a vector-3. + */ + public V3 tail() { + return tail; + } + + /** + * Returns the first element of this vector, as a product-1. + * + * @return the first element of this vector, as a product-1. + */ + public P1 head() { + return head; + } + + /** + * Returns an iterator for the elements of this vector. + * + * @return an iterator for the elements of this vector. + */ + public Iterator iterator() { + return toStream().iterator(); + } + + /** + * Returns a homogeneous product-4 equivalent to this vector. + * + * @return a homogeneous product-4 equivalent to this vector. + */ + public P4 p() { + return new P4() { + public A _1() { + return V4.this._1(); + } + + public A _2() { + return V4.this._2(); + } + + public A _3() { + return V4.this._3(); + } + + public A _4() { + return V4.this._4(); + } + }; + } + + /** + * Returns a nonempty list with the elements of this vector. + * + * @return a nonempty list with the elements of this vector. + */ + public NonEmptyList toNonEmptyList() { + return NonEmptyList.nel(_1(), tail.toNonEmptyList().toList()); + } + + /** + * Returns a stream of the elements of this vector. + * + * @return a stream of the elements of this vector. + */ + public Stream toStream() { + return Stream.cons(head._1(), new P1>() { + public Stream _1() { + return tail.toStream(); + } + }); + } + + /** + * Returns an array with the elements of this vector. + * + * @return an array with the elements of this vector. + */ + @SuppressWarnings("unchecked") + public Array toArray() { + return Array.array(_1(), _2(), _3(), _4()); + } + + /** + * Maps the given function across this vector. + * + * @param f The function to map across this vector. + * @return A new vector after the given function has been applied to each element. + */ + public V4 map(final F f) { + return new V4(head.map(f), tail.map(f)); + } + + /** + * Performs function application within a vector (applicative functor pattern). + * + * @param vf The vector of functions to apply. + * @return A new vector after zipping the given vector of functions over this vector. + */ + public V4 apply(final V4> vf) { + return new V4(head.apply(vf.head()), tail.apply(vf.tail())); + } + + /** + * Zips this vector with the given vector using the given function to produce a new vector. + * + * @param bs The vector to zip this vector with. + * @param f The function to zip this vector and the given vector with. + * @return A new vector with the results of the function. + */ + public V4 zipWith(final F> f, final V4 bs) { + return bs.apply(map(f)); + } + + /** + * Zips this vector with the given vector to produce a vector of pairs. + * + * @param bs The vector to zip this vector with. + * @return A new vector with a length the same as the shortest of this vector and the given + * vector. + */ + public V4> zip(final V4 bs) { + final F>> __2 = p2(); + return zipWith(__2, bs); + } + + /** + * Zips this vector with the given vector to produce a vector of vectors. + * + * @param bs The vector to zip this vector with. + * @return A new vector of vectors. + */ + public V4> vzip(final V4 bs) { + final F2> __2 = V.v2(); + return zipWith(curry(__2), bs); + } + + /** + * Returns a function that transforms a vector-4 to a stream of its elements. + * + * @return a function that transforms a vector-4 to a stream of its elements. + */ + public static F, Stream> toStream_() { + return new F, Stream>() { + public Stream f(final V4 v) { + return v.toStream(); + } + }; + } + + /** + * Returns a function that transforms a vector-4 to the equivalent product-4. + * + * @return a function that transforms a vector-4 to the equivalent product-4. + */ + public static F, P4> p_() { + return new F, P4>() { + public P4 f(final V4 v) { + return v.p(); + } + }; + } + + /** + * A first-class function to get the first element of a vector. + * + * @return a function that gets the first element of a given vector. + */ + public static F, A> __1() { + return new F, A>() { + public A f(final V4 v) { + return v._1(); + } + }; + } + + /** + * A first-class function to get the second element of a vector. + * + * @return a function that gets the second element of a given vector. + */ + public static F, A> __2() { + return new F, A>() { + public A f(final V4 v) { + return v._2(); + } + }; + } + + /** + * A first-class function to get the third element of a vector. + * + * @return a function that gets the third element of a given vector. + */ + public static F, A> __3() { + return new F, A>() { + public A f(final V4 v) { + return v._3(); + } + }; + } + + /** + * A first-class function to get the fourth element of a vector. + * + * @return a function that gets the fourth element of a given vector. + */ + public static F, A> __4() { + return new F, A>() { + public A f(final V4 v) { + return v._4(); + } + }; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/vector/V5.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/vector/V5.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,348 @@ +package fj.data.vector; + +import fj.F; +import fj.F2; +import fj.P1; +import fj.P2; +import fj.P4; +import fj.P5; +import static fj.Function.curry; +import static fj.P.p2; +import fj.data.Array; +import fj.data.NonEmptyList; +import fj.data.Stream; + +import java.util.Iterator; + +/** + * A vector-5. + */ +public final class V5 implements Iterable { + + private final V4 tail; + private final P1 head; + + private V5(final P1 head, final V4 tail) { + this.head = head; + this.tail = tail; + } + + /** + * Creates a vector-5 from a homogeneous product-5. + * + * @param p The product-5 from which to create a vector. + * @return A new vector-5. + */ + public static V5 p(final P5 p) { + return new V5(new P1() { + public A _1() { + return p._1(); + } + }, V4.p(new P4() { + public A _1() { + return p._2(); + } + + public A _2() { + return p._3(); + } + + public A _3() { + return p._4(); + } + + public A _4() { + return p._5(); + } + })); + } + + /** + * Creates a vector-5 from a head and a tail. + * + * @param head The value to put as the first element of the vector. + * @param tail The vector representing all but the first element of the new vector. + * @return The new vector. + */ + public static V5 cons(final P1 head, final V4 tail) { + return new V5(head, tail); + } + + /** + * Returns the first element of this vector. + * + * @return the first element of this vector. + */ + public A _1() { + return head._1(); + } + + /** + * Returns the second element of this vector. + * + * @return the second element of this vector. + */ + public A _2() { + return tail._1(); + } + + /** + * Returns the third element of this vector. + * + * @return the third element of this vector. + */ + public A _3() { + return tail._2(); + } + + /** + * Returns the fourth element of this vector. + * + * @return the fourth element of this vector. + */ + public A _4() { + return tail._3(); + } + + /** + * Returns the fifth element of this vector. + * + * @return the fifth element of this vector. + */ + public A _5() { + return tail._4(); + } + + /** + * Returns all but the first element of this vector, as a vector-4. + * + * @return all but the first element of this vector, as a vector-4. + */ + public V4 tail() { + return tail; + } + + /** + * Returns the first element of this vector, as a product-1. + * + * @return the first element of this vector, as a product-1. + */ + public P1 head() { + return head; + } + + /** + * Returns an iterator for the elements of this vector. + * + * @return an iterator for the elements of this vector. + */ + public Iterator iterator() { + return toStream().iterator(); + } + + /** + * Returns a homogeneous product-5 equivalent to this vector. + * + * @return a homogeneous product-5 equivalent to this vector. + */ + public P5 p() { + return new P5() { + public A _1() { + return V5.this._1(); + } + + public A _2() { + return V5.this._2(); + } + + public A _3() { + return V5.this._3(); + } + + public A _4() { + return V5.this._4(); + } + + public A _5() { + return V5.this._5(); + } + }; + } + + /** + * Returns a nonempty list with the elements of this vector. + * + * @return a nonempty list with the elements of this vector. + */ + public NonEmptyList toNonEmptyList() { + return NonEmptyList.nel(_1(), tail.toNonEmptyList().toList()); + } + + /** + * Returns a stream of the elements of this vector. + * + * @return a stream of the elements of this vector. + */ + public Stream toStream() { + return Stream.cons(head._1(), new P1>() { + public Stream _1() { + return tail.toStream(); + } + }); + } + + /** + * Returns an array with the elements of this vector. + * + * @return an array with the elements of this vector. + */ + @SuppressWarnings("unchecked") + public Array toArray() { + return Array.array(_1(), _2(), _3(), _4(), _5()); + } + + /** + * Maps the given function across this vector. + * + * @param f The function to map across this vector. + * @return A new vector after the given function has been applied to each element. + */ + public V5 map(final F f) { + return new V5(head.map(f), tail.map(f)); + } + + /** + * Performs function application within a vector (applicative functor pattern). + * + * @param vf The vector of functions to apply. + * @return A new vector after zipping the given vector of functions over this vector. + */ + public V5 apply(final V5> vf) { + return new V5(head.apply(vf.head()), tail.apply(vf.tail())); + } + + /** + * Zips this vector with the given vector using the given function to produce a new vector. + * + * @param bs The vector to zip this vector with. + * @param f The function to zip this vector and the given vector with. + * @return A new vector with the results of the function. + */ + public V5 zipWith(final F> f, final V5 bs) { + return bs.apply(map(f)); + } + + /** + * Zips this vector with the given vector to produce a vector of pairs. + * + * @param bs The vector to zip this vector with. + * @return A new vector with a length the same as the shortest of this vector and the given + * vector. + */ + public V5> zip(final V5 bs) { + final F>> __2 = p2(); + return zipWith(__2, bs); + } + + /** + * Zips this vector with the given vector to produce a vector of vectors. + * + * @param bs The vector to zip this vector with. + * @return A new vector of vectors. + */ + public V5> vzip(final V5 bs) { + final F2> __2 = V.v2(); + return zipWith(curry(__2), bs); + } + + /** + * Returns a function that transforms a vector-5 to a stream of its elements. + * + * @return a function that transforms a vector-5 to a stream of its elements. + */ + public static F, Stream> toStream_() { + return new F, Stream>() { + public Stream f(final V5 v) { + return v.toStream(); + } + }; + } + + /** + * Returns a function that transforms a vector-5 to the equivalent product-5. + * + * @return a function that transforms a vector-5 to the equivalent product-5. + */ + public static F, P5> p_() { + return new F, P5>() { + public P5 f(final V5 v) { + return v.p(); + } + }; + } + + /** + * A first-class function to get the first element of a vector. + * + * @return a function that gets the first element of a given vector. + */ + public static F, A> __1() { + return new F, A>() { + public A f(final V5 v) { + return v._1(); + } + }; + } + + /** + * A first-class function to get the second element of a vector. + * + * @return a function that gets the second element of a given vector. + */ + public static F, A> __2() { + return new F, A>() { + public A f(final V5 v) { + return v._2(); + } + }; + } + + /** + * A first-class function to get the third element of a vector. + * + * @return a function that gets the third element of a given vector. + */ + public static F, A> __3() { + return new F, A>() { + public A f(final V5 v) { + return v._3(); + } + }; + } + + /** + * A first-class function to get the fourth element of a vector. + * + * @return a function that gets the fourth element of a given vector. + */ + public static F, A> __4() { + return new F, A>() { + public A f(final V5 v) { + return v._4(); + } + }; + } + + /** + * A first-class function to get the fifth element of a vector. + * + * @return a function that gets the fifth element of a given vector. + */ + public static F, A> __5() { + return new F, A>() { + public A f(final V5 v) { + return v._5(); + } + }; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/vector/V6.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/vector/V6.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,379 @@ +package fj.data.vector; + +import fj.F; +import fj.F2; +import fj.P1; +import fj.P2; +import fj.P5; +import fj.P6; +import static fj.Function.curry; +import static fj.P.p2; +import fj.data.Array; +import fj.data.NonEmptyList; +import fj.data.Stream; + +import java.util.Iterator; + +/** + * A vector-6. + */ +public final class V6 implements Iterable { + + private final V5 tail; + private final P1 head; + + private V6(final P1 head, final V5 tail) { + this.head = head; + this.tail = tail; + } + + /** + * Creates a vector-6 from a homogeneous product-6. + * + * @param p The product-6 from which to create a vector. + * @return A new vector-6. + */ + public static V6 p(final P6 p) { + return new V6(new P1() { + public A _1() { + return p._1(); + } + }, V5.p(new P5() { + public A _1() { + return p._2(); + } + + public A _2() { + return p._3(); + } + + public A _3() { + return p._4(); + } + + public A _4() { + return p._5(); + } + + public A _5() { + return p._6(); + } + })); + } + + /** + * Creates a vector-6 from a head and a tail. + * + * @param head The value to put as the first element of the vector. + * @param tail The vector representing all but the first element of the new vector. + * @return The new vector. + */ + public static V6 cons(final P1 head, final V5 tail) { + return new V6(head, tail); + } + + /** + * Returns the first element of this vector. + * + * @return the first element of this vector. + */ + public A _1() { + return head._1(); + } + + /** + * Returns the second element of this vector. + * + * @return the second element of this vector. + */ + public A _2() { + return tail._1(); + } + + /** + * Returns the third element of this vector. + * + * @return the third element of this vector. + */ + public A _3() { + return tail._2(); + } + + /** + * Returns the fourth element of this vector. + * + * @return the fourth element of this vector. + */ + public A _4() { + return tail._3(); + } + + /** + * Returns the fifth element of this vector. + * + * @return the fifth element of this vector. + */ + public A _5() { + return tail._4(); + } + + /** + * Returns the sixth element of this vector. + * + * @return the sixth element of this vector. + */ + public A _6() { + return tail._5(); + } + + /** + * Returns all but the first element of this vector, as a vector-5. + * + * @return all but the first element of this vector, as a vector-5. + */ + public V5 tail() { + return tail; + } + + /** + * Returns the first element of this vector, as a product-1. + * + * @return the first element of this vector, as a product-1. + */ + public P1 head() { + return head; + } + + /** + * Returns an iterator for the elements of this vector. + * + * @return an iterator for the elements of this vector. + */ + public Iterator iterator() { + return toStream().iterator(); + } + + /** + * Returns a homogeneous product-6 equivalent to this vector. + * + * @return a homogeneous product-6 equivalent to this vector. + */ + public P6 p() { + return new P6() { + public A _1() { + return V6.this._1(); + } + + public A _2() { + return V6.this._2(); + } + + public A _3() { + return V6.this._3(); + } + + public A _4() { + return V6.this._4(); + } + + public A _5() { + return V6.this._5(); + } + + public A _6() { + return V6.this._6(); + } + }; + } + + /** + * Returns a nonempty list with the elements of this vector. + * + * @return a nonempty list with the elements of this vector. + */ + public NonEmptyList toNonEmptyList() { + return NonEmptyList.nel(_1(), tail.toNonEmptyList().toList()); + } + + /** + * Returns a stream of the elements of this vector. + * + * @return a stream of the elements of this vector. + */ + public Stream toStream() { + return Stream.cons(head._1(), new P1>() { + public Stream _1() { + return tail.toStream(); + } + }); + } + + /** + * Returns an array with the elements of this vector. + * + * @return an array with the elements of this vector. + */ + @SuppressWarnings("unchecked") + public Array toArray() { + return Array.array(_1(), _2(), _3(), _4(), _5(), _6()); + } + + /** + * Maps the given function across this vector. + * + * @param f The function to map across this vector. + * @return A new vector after the given function has been applied to each element. + */ + public V6 map(final F f) { + return new V6(head.map(f), tail.map(f)); + } + + /** + * Performs function application within a vector (applicative functor pattern). + * + * @param vf The vector of functions to apply. + * @return A new vector after zipping the given vector of functions over this vector. + */ + public V6 apply(final V6> vf) { + return new V6(head.apply(vf.head()), tail.apply(vf.tail())); + } + + /** + * Zips this vector with the given vector using the given function to produce a new vector. + * + * @param bs The vector to zip this vector with. + * @param f The function to zip this vector and the given vector with. + * @return A new vector with the results of the function. + */ + public V6 zipWith(final F> f, final V6 bs) { + return bs.apply(map(f)); + } + + /** + * Zips this vector with the given vector to produce a vector of pairs. + * + * @param bs The vector to zip this vector with. + * @return A new vector with a length the same as the shortest of this vector and the given + * vector. + */ + public V6> zip(final V6 bs) { + final F>> __2 = p2(); + return zipWith(__2, bs); + } + + /** + * Zips this vector with the given vector to produce a vector of vectors. + * + * @param bs The vector to zip this vector with. + * @return A new vector of vectors. + */ + public V6> vzip(final V6 bs) { + final F2> __2 = V.v2(); + return zipWith(curry(__2), bs); + } + + /** + * Returns a function that transforms a vector-6 to a stream of its elements. + * + * @return a function that transforms a vector-6 to a stream of its elements. + */ + public static F, Stream> toStream_() { + return new F, Stream>() { + public Stream f(final V6 v) { + return v.toStream(); + } + }; + } + + /** + * Returns a function that transforms a vector-6 to the equivalent product-6. + * + * @return a function that transforms a vector-6 to the equivalent product-6. + */ + public static F, P6> p_() { + return new F, P6>() { + public P6 f(final V6 v) { + return v.p(); + } + }; + } + + /** + * A first-class function to get the first element of a vector. + * + * @return a function that gets the first element of a given vector. + */ + public static F, A> __1() { + return new F, A>() { + public A f(final V6 v) { + return v._1(); + } + }; + } + + /** + * A first-class function to get the second element of a vector. + * + * @return a function that gets the second element of a given vector. + */ + public static F, A> __2() { + return new F, A>() { + public A f(final V6 v) { + return v._2(); + } + }; + } + + /** + * A first-class function to get the third element of a vector. + * + * @return a function that gets the third element of a given vector. + */ + public static F, A> __3() { + return new F, A>() { + public A f(final V6 v) { + return v._3(); + } + }; + } + + /** + * A first-class function to get the fourth element of a vector. + * + * @return a function that gets the fourth element of a given vector. + */ + public static F, A> __4() { + return new F, A>() { + public A f(final V6 v) { + return v._4(); + } + }; + } + + /** + * A first-class function to get the fifth element of a vector. + * + * @return a function that gets the fifth element of a given vector. + */ + public static F, A> __5() { + return new F, A>() { + public A f(final V6 v) { + return v._5(); + } + }; + } + + /** + * A first-class function to get the sixth element of a vector. + * + * @return a function that gets the sixth element of a given vector. + */ + public static F, A> __6() { + return new F, A>() { + public A f(final V6 v) { + return v._6(); + } + }; + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/vector/V7.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/vector/V7.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,409 @@ +package fj.data.vector; + +import fj.F; +import fj.F2; +import fj.P1; +import fj.P2; +import fj.P6; +import fj.P7; +import static fj.Function.curry; +import static fj.P.p2; +import fj.data.Array; +import fj.data.NonEmptyList; +import fj.data.Stream; + +import java.util.Iterator; + +/** + * A vector-7. + */ +public final class V7 implements Iterable { + + private final V6 tail; + private final P1 head; + + private V7(final P1 head, final V6 tail) { + this.head = head; + this.tail = tail; + } + + /** + * Creates a vector-7 from a homogeneous product-7. + * + * @param p The product-7 from which to create a vector. + * @return A new vector-7. + */ + public static V7 p(final P7 p) { + return new V7(new P1() { + public A _1() { + return p._1(); + } + }, V6.p(new P6() { + public A _1() { + return p._2(); + } + + public A _2() { + return p._3(); + } + + public A _3() { + return p._4(); + } + + public A _4() { + return p._5(); + } + + public A _5() { + return p._6(); + } + + public A _6() { + return p._7(); + } + })); + } + + /** + * Creates a vector-7 from a head and a tail. + * + * @param head The value to put as the first element of the vector. + * @param tail The vector representing all but the first element of the new vector. + * @return The new vector. + */ + public static V7 cons(final P1 head, final V6 tail) { + return new V7(head, tail); + } + + /** + * Returns the first element of this vector. + * + * @return the first element of this vector. + */ + public A _1() { + return head._1(); + } + + /** + * Returns the second element of this vector. + * + * @return the second element of this vector. + */ + public A _2() { + return tail._1(); + } + + /** + * Returns the third element of this vector. + * + * @return the third element of this vector. + */ + public A _3() { + return tail._2(); + } + + /** + * Returns the fourth element of this vector. + * + * @return the fourth element of this vector. + */ + public A _4() { + return tail._3(); + } + + /** + * Returns the fifth element of this vector. + * + * @return the fifth element of this vector. + */ + public A _5() { + return tail._4(); + } + + /** + * Returns the sixth element of this vector. + * + * @return the sixth element of this vector. + */ + public A _6() { + return tail._5(); + } + + /** + * Returns the seventh element of this vector. + * + * @return the seventh element of this vector. + */ + public A _7() { + return tail._6(); + } + + /** + * Returns all but the first element of this vector, as a vector-6. + * + * @return all but the first element of this vector, as a vector-6. + */ + public V6 tail() { + return tail; + } + + /** + * Returns the first element of this vector, as a product-1. + * + * @return the first element of this vector, as a product-1. + */ + public P1 head() { + return head; + } + + /** + * Returns an iterator for the elements of this vector. + * + * @return an iterator for the elements of this vector. + */ + public Iterator iterator() { + return toStream().iterator(); + } + + /** + * Returns a homogeneous product-7 equivalent to this vector. + * + * @return a homogeneous product-7 equivalent to this vector. + */ + public P7 p() { + return new P7() { + public A _1() { + return V7.this._1(); + } + + public A _2() { + return V7.this._2(); + } + + public A _3() { + return V7.this._3(); + } + + public A _4() { + return V7.this._4(); + } + + public A _5() { + return V7.this._5(); + } + + public A _6() { + return V7.this._6(); + } + + public A _7() { + return V7.this._7(); + } + }; + } + + /** + * Returns a nonempty list with the elements of this vector. + * + * @return a nonempty list with the elements of this vector. + */ + public NonEmptyList toNonEmptyList() { + return NonEmptyList.nel(_1(), tail.toNonEmptyList().toList()); + } + + /** + * Returns a stream of the elements of this vector. + * + * @return a stream of the elements of this vector. + */ + public Stream toStream() { + return Stream.cons(head._1(), new P1>() { + public Stream _1() { + return tail.toStream(); + } + }); + } + + /** + * Returns an array with the elements of this vector. + * + * @return an array with the elements of this vector. + */ + @SuppressWarnings("unchecked") + public Array toArray() { + return Array.array(_1(), _2(), _3(), _4(), _5(), _6(), _7()); + } + + /** + * Maps the given function across this vector. + * + * @param f The function to map across this vector. + * @return A new vector after the given function has been applied to each element. + */ + public V7 map(final F f) { + return new V7(head.map(f), tail.map(f)); + } + + /** + * Performs function application within a vector (applicative functor pattern). + * + * @param vf The vector of functions to apply. + * @return A new vector after zipping the given vector of functions over this vector. + */ + public V7 apply(final V7> vf) { + return new V7(head.apply(vf.head()), tail.apply(vf.tail())); + } + + /** + * Zips this vector with the given vector using the given function to produce a new vector. + * + * @param bs The vector to zip this vector with. + * @param f The function to zip this vector and the given vector with. + * @return A new vector with the results of the function. + */ + public V7 zipWith(final F> f, final V7 bs) { + return bs.apply(map(f)); + } + + /** + * Zips this vector with the given vector to produce a vector of pairs. + * + * @param bs The vector to zip this vector with. + * @return A new vector with a length the same as the shortest of this vector and the given + * vector. + */ + public V7> zip(final V7 bs) { + final F>> __2 = p2(); + return zipWith(__2, bs); + } + + /** + * Zips this vector with the given vector to produce a vector of vectors. + * + * @param bs The vector to zip this vector with. + * @return A new vector of vectors. + */ + public V7> vzip(final V7 bs) { + final F2> __2 = V.v2(); + return zipWith(curry(__2), bs); + } + + /** + * Returns a function that transforms a vector-7 to a stream of its elements. + * + * @return a function that transforms a vector-7 to a stream of its elements. + */ + public static F, Stream> toStream_() { + return new F, Stream>() { + public Stream f(final V7 v) { + return v.toStream(); + } + }; + } + + /** + * Returns a function that transforms a vector-7 to the equivalent product-7. + * + * @return a function that transforms a vector-7 to the equivalent product-7. + */ + public static F, P7> p_() { + return new F, P7>() { + public P7 f(final V7 v) { + return v.p(); + } + }; + } + + /** + * A first-class function to get the first element of a vector. + * + * @return a function that gets the first element of a given vector. + */ + public static F, A> __1() { + return new F, A>() { + public A f(final V7 v) { + return v._1(); + } + }; + } + + /** + * A first-class function to get the second element of a vector. + * + * @return a function that gets the second element of a given vector. + */ + public static F, A> __2() { + return new F, A>() { + public A f(final V7 v) { + return v._2(); + } + }; + } + + /** + * A first-class function to get the third element of a vector. + * + * @return a function that gets the third element of a given vector. + */ + public static F, A> __3() { + return new F, A>() { + public A f(final V7 v) { + return v._3(); + } + }; + } + + /** + * A first-class function to get the fourth element of a vector. + * + * @return a function that gets the fourth element of a given vector. + */ + public static F, A> __4() { + return new F, A>() { + public A f(final V7 v) { + return v._4(); + } + }; + } + + /** + * A first-class function to get the fifth element of a vector. + * + * @return a function that gets the fifth element of a given vector. + */ + public static F, A> __5() { + return new F, A>() { + public A f(final V7 v) { + return v._5(); + } + }; + } + + /** + * A first-class function to get the sixth element of a vector. + * + * @return a function that gets the sixth element of a given vector. + */ + public static F, A> __6() { + return new F, A>() { + public A f(final V7 v) { + return v._6(); + } + }; + } + + /** + * A first-class function to get the seventh element of a vector. + * + * @return a function that gets the seventh element of a given vector. + */ + public static F, A> __7() { + return new F, A>() { + public A f(final V7 v) { + return v._7(); + } + }; + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/vector/V8.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/vector/V8.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,440 @@ +package fj.data.vector; + +import fj.F; +import fj.F2; +import fj.P1; +import fj.P2; +import fj.P7; +import fj.P8; +import static fj.Function.curry; +import static fj.P.p2; +import fj.data.Array; +import fj.data.NonEmptyList; +import fj.data.Stream; + +import java.util.Iterator; + +/** + * A vector-8. + */ +public final class V8 implements Iterable { + + private final V7 tail; + private final P1 head; + + private V8(final P1 head, final V7 tail) { + this.head = head; + this.tail = tail; + } + + /** + * Creates a vector-8 from a homogeneous product-8. + * + * @param p The product-8 from which to create a vector. + * @return A new vector-8. + */ + public static V8 p(final P8 p) { + return new V8(new P1() { + public A _1() { + return p._1(); + } + }, V7.p(new P7() { + public A _1() { + return p._2(); + } + + public A _2() { + return p._3(); + } + + public A _3() { + return p._4(); + } + + public A _4() { + return p._5(); + } + + public A _5() { + return p._6(); + } + + public A _6() { + return p._7(); + } + + public A _7() { + return p._8(); + } + })); + } + + /** + * Creates a vector-8 from a head and a tail. + * + * @param head The value to put as the first element of the vector. + * @param tail The vector representing all but the first element of the new vector. + * @return The new vector. + */ + public static V8 cons(final P1 head, final V7 tail) { + return new V8(head, tail); + } + + /** + * Returns the first element of this vector. + * + * @return the first element of this vector. + */ + public A _1() { + return head._1(); + } + + /** + * Returns the second element of this vector. + * + * @return the second element of this vector. + */ + public A _2() { + return tail._1(); + } + + /** + * Returns the third element of this vector. + * + * @return the third element of this vector. + */ + public A _3() { + return tail._2(); + } + + /** + * Returns the fourth element of this vector. + * + * @return the fourth element of this vector. + */ + public A _4() { + return tail._3(); + } + + /** + * Returns the fifth element of this vector. + * + * @return the fifth element of this vector. + */ + public A _5() { + return tail._4(); + } + + /** + * Returns the sixth element of this vector. + * + * @return the sixth element of this vector. + */ + public A _6() { + return tail._5(); + } + + /** + * Returns the seventh element of this vector. + * + * @return the seventh element of this vector. + */ + public A _7() { + return tail._6(); + } + + /** + * Returns the eighth element of this vector. + * + * @return the eighth element of this vector. + */ + public A _8() { + return tail._7(); + } + + /** + * Returns all but the first element of this vector, as a vector-7. + * + * @return all but the first element of this vector, as a vector-7. + */ + public V7 tail() { + return tail; + } + + /** + * Returns the first element of this vector, as a product-1. + * + * @return the first element of this vector, as a product-1. + */ + public P1 head() { + return head; + } + + /** + * Returns an iterator for the elements of this vector. + * + * @return an iterator for the elements of this vector. + */ + public Iterator iterator() { + return toStream().iterator(); + } + + /** + * Returns a homogeneous product-8 equivalent to this vector. + * + * @return a homogeneous product-8 equivalent to this vector. + */ + public P8 p() { + return new P8() { + public A _1() { + return V8.this._1(); + } + + public A _2() { + return V8.this._2(); + } + + public A _3() { + return V8.this._3(); + } + + public A _4() { + return V8.this._4(); + } + + public A _5() { + return V8.this._5(); + } + + public A _6() { + return V8.this._6(); + } + + public A _7() { + return V8.this._7(); + } + + public A _8() { + return V8.this._8(); + } + }; + } + + /** + * Returns a nonempty list with the elements of this vector. + * + * @return a nonempty list with the elements of this vector. + */ + public NonEmptyList toNonEmptyList() { + return NonEmptyList.nel(_1(), tail.toNonEmptyList().toList()); + } + + /** + * Returns a stream of the elements of this vector. + * + * @return a stream of the elements of this vector. + */ + public Stream toStream() { + return Stream.cons(head._1(), new P1>() { + public Stream _1() { + return tail.toStream(); + } + }); + } + + /** + * Returns an array with the elements of this vector. + * + * @return an array with the elements of this vector. + */ + @SuppressWarnings("unchecked") + public Array toArray() { + return Array.array(_1(), _2(), _3(), _4(), _5(), _6(), _7(), _8()); + } + + /** + * Maps the given function across this vector. + * + * @param f The function to map across this vector. + * @return A new vector after the given function has been applied to each element. + */ + public V8 map(final F f) { + return new V8(head.map(f), tail.map(f)); + } + + /** + * Performs function application within a vector (applicative functor pattern). + * + * @param vf The vector of functions to apply. + * @return A new vector after zipping the given vector of functions over this vector. + */ + public V8 apply(final V8> vf) { + return new V8(head.apply(vf.head()), tail.apply(vf.tail())); + } + + /** + * Zips this vector with the given vector using the given function to produce a new vector. + * + * @param bs The vector to zip this vector with. + * @param f The function to zip this vector and the given vector with. + * @return A new vector with the results of the function. + */ + public V8 zipWith(final F> f, final V8 bs) { + return bs.apply(map(f)); + } + + /** + * Zips this vector with the given vector to produce a vector of pairs. + * + * @param bs The vector to zip this vector with. + * @return A new vector with a length the same as the shortest of this vector and the given + * vector. + */ + public V8> zip(final V8 bs) { + final F>> __2 = p2(); + return zipWith(__2, bs); + } + + /** + * Zips this vector with the given vector to produce a vector of vectors. + * + * @param bs The vector to zip this vector with. + * @return A new vector of vectors. + */ + public V8> vzip(final V8 bs) { + final F2> __2 = V.v2(); + return zipWith(curry(__2), bs); + } + + /** + * Returns a function that transforms a vector-8 to a stream of its elements. + * + * @return a function that transforms a vector-8 to a stream of its elements. + */ + public static F, Stream> toStream_() { + return new F, Stream>() { + public Stream f(final V8 v) { + return v.toStream(); + } + }; + } + + /** + * Returns a function that transforms a vector-8 to the equivalent product-8. + * + * @return a function that transforms a vector-8 to the equivalent product-8. + */ + public static F, P8> p_() { + return new F, P8>() { + public P8 f(final V8 v) { + return v.p(); + } + }; + } + + + /** + * A first-class function to get the first element of a vector. + * + * @return a function that gets the first element of a given vector. + */ + public static F, A> __1() { + return new F, A>() { + public A f(final V8 v) { + return v._1(); + } + }; + } + + /** + * A first-class function to get the second element of a vector. + * + * @return a function that gets the second element of a given vector. + */ + public static F, A> __2() { + return new F, A>() { + public A f(final V8 v) { + return v._2(); + } + }; + } + + /** + * A first-class function to get the third element of a vector. + * + * @return a function that gets the third element of a given vector. + */ + public static F, A> __3() { + return new F, A>() { + public A f(final V8 v) { + return v._3(); + } + }; + } + + /** + * A first-class function to get the fourth element of a vector. + * + * @return a function that gets the fourth element of a given vector. + */ + public static F, A> __4() { + return new F, A>() { + public A f(final V8 v) { + return v._4(); + } + }; + } + + /** + * A first-class function to get the fifth element of a vector. + * + * @return a function that gets the fifth element of a given vector. + */ + public static F, A> __5() { + return new F, A>() { + public A f(final V8 v) { + return v._5(); + } + }; + } + + /** + * A first-class function to get the sixth element of a vector. + * + * @return a function that gets the sixth element of a given vector. + */ + public static F, A> __6() { + return new F, A>() { + public A f(final V8 v) { + return v._6(); + } + }; + } + + /** + * A first-class function to get the seventh element of a vector. + * + * @return a function that gets the seventh element of a given vector. + */ + public static F, A> __7() { + return new F, A>() { + public A f(final V8 v) { + return v._7(); + } + }; + } + + /** + * A first-class function to get the eighth element of a vector. + * + * @return a function that gets the eighth element of a given vector. + */ + public static F, A> __8() { + return new F, A>() { + public A f(final V8 v) { + return v._8(); + } + }; + } + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/data/vector/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/vector/package-info.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,6 @@ +/** + * Fixed-length vectors + * + * @version %build.number% + */ +package fj.data.vector; diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/BigIntegers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/BigIntegers.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,107 @@ +package fj.function; + +import fj.F; +import fj.F2; +import fj.Monoid; +import fj.data.List; +import static fj.Function.curry; + +import java.math.BigInteger; + +/** + * Curried functions over Integers. + * + * @version %build.number% + */ +public final class BigIntegers { + private BigIntegers() { + throw new UnsupportedOperationException(); + } + + /** + * Curried Integer addition. + */ + public static final F> add = + curry(new F2() { + public BigInteger f(final BigInteger a1, final BigInteger a2) { + return a1.add(a2); + } + }); + + /** + * Curried Integer multiplication. + */ + public static final F> multiply = + curry(new F2() { + public BigInteger f(final BigInteger a1, final BigInteger a2) { + return a1.multiply(a2); + } + }); + + /** + * Curried Integer subtraction. + */ + public static final F> subtract = + curry(new F2() { + public BigInteger f(final BigInteger a1, final BigInteger a2) { + return a1.subtract(a2); + } + }); + + /** + * Negation. + */ + public static final F negate = new F() { + public BigInteger f(final BigInteger i) { + return i.negate(); + } + }; + + /** + * Absolute value. + */ + public static final F abs = new F() { + public BigInteger f(final BigInteger i) { + return i.abs(); + } + }; + + /** + * Remainder. + */ + public static final F> remainder = + curry(new F2() { + public BigInteger f(final BigInteger a1, final BigInteger a2) { + return a1.remainder(a2); + } + }); + + /** + * Power. + */ + public static final F> power = curry(new F2() { + public BigInteger f(final BigInteger a1, final Integer a2) { + return a1.pow(a2); + } + }); + + /** + * Sums a list of big integers. + * + * @param ints A list of big integers to sum. + * @return The sum of the big integers in the list. + */ + public static BigInteger sum(final List ints) { + return Monoid.bigintAdditionMonoid.sumLeft(ints); + } + + /** + * Returns the product of a list of big integers. + * + * @param ints A list of big integers to multiply together. + * @return The product of the big integers in the list. + */ + public static BigInteger product(final List ints) { + return Monoid.bigintMultiplicationMonoid.sumLeft(ints); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Booleans.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Booleans.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,148 @@ +package fj.function; + +import fj.F; +import fj.F2; +import fj.F3; +import static fj.Function.*; + +import fj.Monoid; +import fj.data.List; +import fj.data.Stream; + +import static fj.Semigroup.disjunctionSemigroup; +import static fj.Semigroup.conjunctionSemigroup; +import static fj.Semigroup.exclusiveDisjunctionSemiGroup; + +/** + * Curried logical functions. + * + * @version %build.number% + */ +public final class Booleans { + private Booleans() { + throw new UnsupportedOperationException(); + } + + /** + * Curried form of logical "inclusive or" (disjunction). + */ + public static final F> or = disjunctionSemigroup.sum(); + + /** + * Curried form of logical "and" (conjunction). + */ + public static final F> and = conjunctionSemigroup.sum(); + + + /** + * Curried form of logical xor (nonequivalence). + */ + public static final F> xor = exclusiveDisjunctionSemiGroup.sum(); + + /** + * Logical negation. + */ + public static final F not = new F() { + public Boolean f(final Boolean p) { + return !p; + } + }; + + /** + * Curried form of logical "only if" (material implication). + */ + public static final F> implies = curry(new F2() { + public Boolean f(final Boolean p, final Boolean q) { + return !p || q; + } + }); + + /** + * Curried form of logical "if" (reverse material implication). + */ + public static final F> if_ = flip(implies); + + /** + * Curried form of logical "if and only if" (biconditional, equivalence). + */ + public static final F> iff = compose2(not, xor); + + /** + * Curried form of logical "not implies" (nonimplication). + */ + public static final F> nimp = compose2(not, implies); + + /** + * Curried form of logical "not if" (reverse nonimplication). + */ + public static final F> nif = compose2(not, if_); + + /** + * Curried form of logical "not or". + */ + public static final F> nor = compose2(not, or); + + /** + * Returns true if all the elements of the given list are true. + * + * @param l A list to check for all the elements being true. + * @return true if all the elements of the given list are true. False otherwise. + */ + public static boolean and(final List l) { + return Monoid.conjunctionMonoid.sumLeft(l); + } + + /** + * Returns true if all the elements of the given stream are true. + * + * @param l A stream to check for all the elements being true. + * @return true if all the elements of the given stream are true. False otherwise. + */ + public static boolean and(final Stream l) { + return Monoid.conjunctionMonoid.sumLeft(l); + } + + /** + * Returns true if any element of the given list is true. + * + * @param l A list to check for any element being true. + * @return true if any element of the given list is true. False otherwise. + */ + public static boolean or(final List l) { + return Monoid.disjunctionMonoid.sumLeft(l); + } + + /** + * Returns true if any element of the given stream is true. + * + * @param l A stream to check for any element being true. + * @return true if any element of the given stream is true. False otherwise. + */ + public static boolean or(final Stream l) { + return Monoid.disjunctionMonoid.sumLeft(l); + } + + /** + * Negates the given predicate. + * + * @param p A predicate to negate. + * @return The negation of the given predicate. + */ + public static F not(final F p) { + return compose(not, p); + } + + /** + * Curried form of conditional. If the first argument is true, returns the second argument, + * otherwise the third argument. + * + * @return A function that returns its second argument if the first argument is true, otherwise the third argument. + */ + public static F>> cond() { + return curry(new F3() { + public A f(final Boolean p, final A a1, final A a2) { + return p ? a1 : a2; + } + }); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Characters.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Characters.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,93 @@ +package fj.function; + +import fj.F; +import fj.F2; + +import static fj.Function.curry; + +/** + * First-class functions on Characters. + */ +public final class Characters { + private Characters() { + throw new UnsupportedOperationException(); + } + public static final F toString = new F() { + public String f(final Character c) {return Character.toString(c);} + }; + public static final F isLowerCase = new F() { + public Boolean f(final Character ch) {return Character.isLowerCase(ch);} + }; + public static final F isUpperCase = new F() { + public Boolean f(final Character ch) {return Character.isUpperCase(ch);} + }; + public static final F isTitleCase = new F() { + public Boolean f(final Character ch) {return Character.isTitleCase(ch);} + }; + public static final F isDigit = new F() { + public Boolean f(final Character ch) {return Character.isDigit(ch);} + }; + public static final F isDefined = new F() { + public Boolean f(final Character ch) {return Character.isDefined(ch);} + }; + public static final F isLetter = new F() { + public Boolean f(final Character ch) {return Character.isLetter(ch);} + }; + public static final F isLetterOrDigit = new F() { + public Boolean f(final Character ch) {return Character.isLetterOrDigit(ch);} + }; + public static final F isJavaIdentifierStart = new F() { + public Boolean f(final Character ch) {return Character.isJavaIdentifierStart(ch);} + }; + public static final F isJavaIdentifierPart = new F() { + public Boolean f(final Character ch) {return Character.isJavaIdentifierPart(ch);} + }; + public static final F isUnicodeIdentifierStart = new F() { + public Boolean f(final Character ch) {return Character.isUnicodeIdentifierStart(ch);} + }; + public static final F isUnicodeIdentifierPart = new F() { + public Boolean f(final Character ch) {return Character.isUnicodeIdentifierPart(ch);} + }; + public static final F isIdentifierIgnorable = new F() { + public Boolean f(final Character ch) {return Character.isIdentifierIgnorable(ch);} + }; + public static final F toLowerCase = new F() { + public Character f(final Character ch) {return Character.toLowerCase(ch);} + }; + public static final F toUpperCase = new F() { + public Character f(final Character ch) {return Character.toUpperCase(ch);} + }; + public static final F toTitleCase = new F() { + public Character f(final Character ch) {return Character.toTitleCase(ch);} + }; + public static final F> digit = curry(new F2() { + public Integer f(final Character ch, final Integer radix) {return Character.digit(ch, radix);} + }); + public static final F getNumericValue = new F() { + public Integer f(final Character ch) {return Character.getNumericValue(ch);} + }; + public static final F isSpaceChar = new F() { + public Boolean f(final Character ch) {return Character.isSpaceChar(ch);} + }; + public static final F isWhitespace = new F() { + public Boolean f(final Character ch) {return Character.isWhitespace(ch);} + }; + public static final F isISOControl = new F() { + public Boolean f(final Character ch) {return Character.isISOControl(ch);} + }; + public static final F getType = new F() { + public Integer f(final Character ch) {return Character.getType(ch);} + }; + public static final F getDirectionality = new F() { + public Byte f(final Character ch) {return Character.getDirectionality(ch);} + }; + public static final F isMirrored = new F() { + public Boolean f(final Character ch) {return Character.isMirrored(ch);} + }; + public static final F reverseBytes = new F() { + public Character f(final Character ch) {return Character.reverseBytes(ch);} + }; + public static final F isNewLine = new F() { + public Boolean f(final Character c) { return c == '\n'; } + }; +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Doubles.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Doubles.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,161 @@ +package fj.function; + +import fj.F; +import fj.F2; +import fj.Monoid; +import fj.data.List; +import fj.data.Option; + +import static fj.Function.curry; +import static fj.Semigroup.doubleAdditionSemigroup; +import static fj.Semigroup.doubleMultiplicationSemigroup; +import static fj.data.Option.none; +import static fj.data.Option.some; +import static java.lang.Math.abs; + +/** + * Curried functions over Doubles. + * + * @version %build.number% + */ +public final class Doubles { + private Doubles() { + throw new UnsupportedOperationException(); + } + + /** + * Curried Double addition. + */ + public static final F> add = doubleAdditionSemigroup.sum(); + + /** + * Curried Double multiplication. + */ + public static final F> multiply = doubleMultiplicationSemigroup.sum(); + + /** + * Curried Double subtraction. + */ + public static final F> subtract = curry(new F2() { + public Double f(final Double x, final Double y) { + return x - y; + } + }); + + /** + * Negation. + */ + public static final F negate = new F() { + public Double f(final Double x) { + return x * -1; + } + }; + + /** + * Absolute value. + */ + public static final F abs = new F() { + public Double f(final Double x) { + return abs(x); + } + }; + + /** + * Remainder. + */ + public static final F> remainder = curry(new F2() { + public Double f(final Double a, final Double b) { + return a % b; + } + }); + + /** + * Power. + */ + public static final F> power = curry(new F2() { + public Double f(final Double a, final Double b) { + return StrictMath.pow(a, b); + } + }); + + /** + * Evenness. + */ + public static final F even = new F() { + public Boolean f(final Double i) { + return i % 2 == 0; + } + }; + + /** + * Sums a list of doubles. + * + * @param doubles A list of doubles to sum. + * @return The sum of the doubless in the list. + */ + public static double sum(final List doubles) { + return Monoid.doubleAdditionMonoid.sumLeft(doubles); + } + + /** + * Returns the product of a list of doubles. + * + * @param doubles A list of doubles to multiply together. + * @return The product of the doubles in the list. + */ + public static double product(final List doubles) { + return Monoid.doubleMultiplicationMonoid.sumLeft(doubles); + } + + /** + * A function that converts strings to doubles. + * + * @return A function that converts strings to doubles. + */ + public static F> fromString() { + return new F>() { + public Option f(final String s) { + try { return some(Double.valueOf(s)); } + catch (final NumberFormatException ignored) { + return none(); + } + } + }; + } + + /** + * A function that returns true if the given double is greater than zero. + */ + public static final F gtZero = new F() { + public Boolean f(final Double i) { + return Double.compare(i, 0) > 0; + } + }; + + /** + * A function that returns true if the given double is greater than or equal to zero. + */ + public static final F gteZero = new F() { + public Boolean f(final Double i) { + return Double.compare(i, 0) >= 0; + } + }; + + /** + * A function that returns true if the given double is less than zero. + */ + public static final F ltZero = new F() { + public Boolean f(final Double i) { + return Double.compare(i, 0) < 0; + } + }; + + /** + * A function that returns true if the given double is less than or equal to zero. + */ + public static final F lteZero = new F() { + public Boolean f(final Double i) { + return Double.compare(i, 0) <= 0; + } + }; +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Effect0.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Effect0.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface Effect0 { + + void f(); + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Effect1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Effect1.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface Effect1 { + + void f(A a); + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Effect2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Effect2.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface Effect2 { + + void f(A a, B b); + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Effect3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Effect3.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,11 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface Effect3 { + + void f(A a, B b, C c); + +} + diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Effect4.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Effect4.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface Effect4 { + + void f(A a, B b, C c, D d); + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Effect5.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Effect5.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface Effect5 { + + void f(A a, B b, C c, D d, E e); + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Effect6.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Effect6.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface Effect6 { + + void f(A a, B b, C c, D d, E e, F f); + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Effect7.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Effect7.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface Effect7 { + + void f(A a, B b, C c, D d, E e, F f, G g); + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Effect8.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Effect8.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface Effect8 { + + void f(A a, B b, C c, D d, E e, F f, G g, H h); + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Integers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Integers.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,162 @@ +package fj.function; + +import fj.F; +import fj.F2; +import static fj.Function.curry; + +import fj.Monoid; +import fj.data.List; +import fj.data.Option; +import static fj.data.Option.some; +import static fj.data.Option.none; +import static fj.Semigroup.intAdditionSemigroup; +import static fj.Semigroup.intMultiplicationSemigroup; + +import static java.lang.Math.abs; + +/** + * Curried functions over Integers. + * + * @version %build.number% + */ +public final class Integers { + private Integers() { + throw new UnsupportedOperationException(); + } + + /** + * Curried Integer addition. + */ + public static final F> add = intAdditionSemigroup.sum(); + + /** + * Curried Integer multiplication. + */ + public static final F> multiply = intMultiplicationSemigroup.sum(); + + /** + * Curried Integer subtraction. + */ + public static final F> subtract = curry(new F2() { + public Integer f(final Integer x, final Integer y) { + return x - y; + } + }); + + /** + * Negation. + */ + public static final F negate = new F() { + public Integer f(final Integer x) { + return x * -1; + } + }; + + /** + * Absolute value. + */ + public static final F abs = new F() { + public Integer f(final Integer x) { + return abs(x); + } + }; + + /** + * Remainder. + */ + public static final F> remainder = curry(new F2() { + public Integer f(final Integer a, final Integer b) { + return a % b; + } + }); + + /** + * Power. + */ + public static final F> power = curry(new F2() { + public Integer f(final Integer a, final Integer b) { + return (int) StrictMath.pow(a, b); + } + }); + + /** + * Evenness. + */ + public static final F even = new F() { + public Boolean f(final Integer i) { + return i % 2 == 0; + } + }; + + /** + * Sums a list of integers. + * + * @param ints A list of integers to sum. + * @return The sum of the integers in the list. + */ + public static int sum(final List ints) { + return Monoid.intAdditionMonoid.sumLeft(ints); + } + + /** + * Returns the product of a list of integers. + * + * @param ints A list of integers to multiply together. + * @return The product of the integers in the list. + */ + public static int product(final List ints) { + return Monoid.intMultiplicationMonoid.sumLeft(ints); + } + + /** + * A function that converts strings to integers. + * + * @return A function that converts strings to integers. + */ + public static F> fromString() { + return new F>() { + public Option f(final String s) { + try { return some(Integer.valueOf(s)); } + catch (final NumberFormatException ignored) { + return none(); + } + } + }; + } + + /** + * A function that returns true if the given integer is greater than zero. + */ + public static final F gtZero = new F() { + public Boolean f(final Integer i) { + return i > 0; + } + }; + + /** + * A function that returns true if the given integer is greater than or equal to zero. + */ + public static final F gteZero = new F() { + public Boolean f(final Integer i) { + return i >= 0; + } + }; + + /** + * A function that returns true if the given integer is less than zero. + */ + public static final F ltZero = new F() { + public Boolean f(final Integer i) { + return i < 0; + } + }; + + /** + * A function that returns true if the given integer is less than or equal to zero. + */ + public static final F lteZero = new F() { + public Boolean f(final Integer i) { + return i <= 0; + } + }; +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Longs.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Longs.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,66 @@ +package fj.function; + +import fj.F; +import fj.F2; +import static fj.Function.curry; +import static fj.Semigroup.longAdditionSemigroup; +import static fj.Semigroup.longMultiplicationSemigroup; + +import static java.lang.Math.abs; + +/** + * Curried functions over Longs. + * + * @version %build.number% + */ +public final class Longs { + private Longs() { + throw new UnsupportedOperationException(); + } + + /** + * Curried Long addition. + */ + public static final F> add = longAdditionSemigroup.sum(); + + /** + * Curried Long multiplication. + */ + public static final F> multiply = longMultiplicationSemigroup.sum(); + + /** + * Curried Long subtraction. + */ + public static final F> subtract = curry(new F2() { + public Long f(final Long x, final Long y) { + return x - y; + } + }); + + /** + * Negation. + */ + public static final F negate = new F() { + public Long f(final Long x) { + return x * -1L; + } + }; + + /** + * Absolute value. + */ + public static final F abs = new F() { + public Long f(final Long x) { + return abs(x); + } + }; + + /** + * Remainder. + */ + public static final F> remainder = curry(new F2() { + public Long f(final Long a, final Long b) { + return a % b; + } + }); +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Strings.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Strings.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,113 @@ +package fj.function; + +import fj.F; +import fj.F2; +import fj.data.Stream; +import static fj.Function.curry; +import static fj.function.Booleans.not; +import static fj.function.Characters.isWhitespace; + +/** + * Curried string functions. + * + * @version %build.number% + */ +public final class Strings { + private Strings() { + throw new UnsupportedOperationException(); + } + + /** + * This function checks if a given String contains any non-whitespace character + * (according to {@link Character#isWhitespace(char)}) and if it's also not + * null and not empty (""). + * + * @see #isNullOrBlank + * @see Character#isWhitespace(char) + * @see Characters#isWhitespace + */ + public static final F isNotNullOrBlank = new F() { + @Override + public Boolean f(final String a) { + return isNotNullOrEmpty.f(a) && Stream.fromString(a).find(not(isWhitespace)).isSome(); + } + }; + + /** + * This function checks if a given String is whitespace (according to {@link Character#isWhitespace(char)}), + * empty ("") or null. + * + * @see #isNotNullOrBlank + * @see Character#isWhitespace(char) + * @see Characters#isWhitespace + */ + public static final F isNullOrBlank = new F() { + @Override + public Boolean f(final String a) { + return isNullOrEmpty.f(a) || Stream.fromString(a).find(not(isWhitespace)).isNone(); + } + }; + + /** + * This function checks if a given String is neither null nor empty. + * + * @see #isNullOrEmpty + */ + public static final F isNotNullOrEmpty = new F() { + @Override + public Boolean f(final String a) { + return a != null && a.length() > 0; + } + }; + + /** + * This function checks if a given String is null or empty ({@link String#isEmpty()}). + * + * @see #isNotNullOrEmpty + */ + public static final F isNullOrEmpty = new F() { + @Override + public Boolean f(final String a) { + return a == null || a.length() == 0; + } + }; + + /** + * A curried version of {@link String#isEmpty()}. + */ + public static final F isEmpty = new F() { + public Boolean f(final String s) { + return s.length() == 0; + } + }; + + /** + * A curried version of {@link String#length()}. + */ + public static final F length = new F() { + public Integer f(final String s) { + return s.length(); + } + }; + + /** + * A curried version of {@link String#contains(CharSequence)}. + * The function returns true if the second argument contains the first. + */ + public static final F> contains = curry(new F2() { + public Boolean f(final String s1, final String s2) { + return s2.contains(s1); + } + }); + + /** + * A curried version of {@link String#matches(String)}. + * The function returns true if the second argument matches the first. + */ + public static final F> matches = curry(new F2() { + public Boolean f(final String s1, final String s2) { + return s2.matches(s1); + } + }); + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Try0.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Try0.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,16 @@ +package fj.function; + +/** + * A product of A which may throw an Exception. + * + * Used to instantiate a lambda that may throw an Exception before converting to a P1. + * + * @see fj.Try#f + * @version %build.number% + */ + +public interface Try0 { + + A f() throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Try1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Try1.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,16 @@ +package fj.function; + +/** + * A transformation function from A to B that may throw an Exception. + * + * Used to instantiate a lambda that may throw an Exception before converting to an F. + * + * @see fj.Try#f + * @version %build.number% + */ + +public interface Try1 { + + B f(A a) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Try2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Try2.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,16 @@ +package fj.function; + +/** + * A transformation function of arity-2 from A and B to C that may throw an Exception. + * + * Used to instantiate a lambda that may throw an Exception before converting to an F2. + * + * @see fj.Try#f + * @version %build.number% + */ + +public interface Try2 { + + C f(A a, B b) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Try3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Try3.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,16 @@ +package fj.function; + +/** + * A transformation function of arity-3 from A, B and C to D that may throw an Exception. + * + * Used to instantiate a lambda that may throw an Exception before converting to an F3. + * + * @see fj.Try#f + * @version %build.number% + */ + +public interface Try3 { + + D f(A a, B b, C c) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Try4.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Try4.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,16 @@ +package fj.function; + +/** + * A transformation function of arity-4 from A, B, C and D to E that may throw an Exception. + * + * Used to instantiate a lambda that may throw an Exception before converting to an F4. + * + * @see fj.Try#f + * @version %build.number% + */ + +public interface Try4 { + + E f(A a, B b, C c, D d) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Try5.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Try5.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,16 @@ +package fj.function; + +/** + * A transformation function of arity-5 from A, B, C, D and E to F that may throw an Exception. + * + * Used to instantiate a lambda that may throw an Exception before converting to an F5. + * + * @see fj.Try#f + * @version %build.number% + */ + +public interface Try5 { + + F f(A a, B b, C c, D d, E e) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Try6.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Try6.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,16 @@ +package fj.function; + +/** + * A transformation function of arity-6 from A, B, C, D, E and F to G that may throw an Exception. + * + * Used to instantiate a lambda that may throw an Exception before converting to an F6. + * + * @see fj.Try#f + * @version %build.number% + */ + +public interface Try6 { + + G f(A a, B b, C c, D d, E e, F f) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Try7.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Try7.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,17 @@ +package fj.function; + + +/** + * A transformation function of arity-7 from A, B, C, D, E, F and G to H that may throw an Exception. + * + * Used to instantiate a lambda that may throw an Exception before converting to an F7. + * + * @see fj.Try#f + * @version %build.number% + */ + +public interface Try7 { + + H f(A a, B b, C c, D d, E e, F f, G g) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Try8.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Try8.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,16 @@ +package fj.function; + +/** + * A transformation function of arity-8 from A, B, C, D, E, F, G and H to I that may throw an Exception. + * + * Used to instantiate a lambda that may throw an Exception before converting to an F8. + * + * @see fj.Try#f + * @version %build.number% + */ + +public interface Try8 { + + I f(A a, B b, C c, D d, E e, F f, G g, H h) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/TryEffect0.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/TryEffect0.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface TryEffect0 { + + void f() throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/TryEffect1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/TryEffect1.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface TryEffect1 { + + void f(A a) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/TryEffect2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/TryEffect2.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface TryEffect2 { + + void f(A a, B b) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/TryEffect3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/TryEffect3.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface TryEffect3 { + + void f(A a, B b, C c) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/TryEffect4.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/TryEffect4.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface TryEffect4 { + + void f(A a, B b, C c, D d) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/TryEffect5.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/TryEffect5.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface TryEffect5 { + + void f(A a, B b, C c, D d, E e) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/TryEffect6.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/TryEffect6.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface TryEffect6 { + + void f(A a, B b, C c, D d, E e, F f) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/TryEffect7.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/TryEffect7.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface TryEffect7 { + + void f(A a, B b, C c, D d, E e, F f, G g) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/TryEffect8.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/TryEffect8.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,10 @@ +package fj.function; + +/** + * Created by mperry on 28/08/2014. + */ +public interface TryEffect8 { + + void f(A a, B b, C c, D d, E e, F f, G g, H h) throws Z; + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/Visitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/Visitor.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,112 @@ +package fj.function; + +import fj.Equal; +import fj.F; +import fj.F2; +import fj.Function; +import fj.Monoid; +import fj.P1; +import fj.P2; +import fj.data.List; +import fj.data.Option; + +import static fj.Function.compose; +import static fj.Function.curry; +import static fj.data.List.lookup; + +/** + * The essence of the visitor design pattern expressed polymorphically. + * + * @version %build.number% + */ +public final class Visitor { + private Visitor() { + throw new UnsupportedOperationException(); + } + + /** + * Returns the first value available in the given list of optional values. If none is found return the given default value. + * + * @param values The optional values to search. + * @param def The default value if no value is found in the list. + * @return The first value available in the given list of optional values. If none is found return the given default value. + */ + public static X findFirst(final List> values, final P1 def) { + return Monoid.firstOptionMonoid().sumLeft(values).orSome(def); + } + + /** + * Returns the first non-null value in the given list of optional values. If none is found return the given default value. + * + * @param values The potentially null values to search. + * @param def The default value if no value is found in the list. + * @return The first non-null value in the given list of optional values. If none is found return the given default value. + */ + public static X nullablefindFirst(final List values, final P1 def) { + return findFirst(values.map(Option.fromNull()), def); + } + + /** + * Returns the first value found in the list of visitors after application of the given value, otherwise returns the + * given default. + * + * @param visitors The list of visitors to apply. + * @param def The default if none of the visitors yield a value. + * @param value The value to apply to the visitors. + * @return The first value found in the list of visitors after application of the given value, otherwise returns the + * given default. + */ + public static B visitor(final List>> visitors, final P1 def, final A value) { + return findFirst(visitors.map(Function.>apply(value)), def); + } + + /** + * Returns the first non-null value found in the list of visitors after application of the given value, + * otherwise returns the given default. + * + * @param visitors The list of visitors to apply looking for a non-null. + * @param def The default if none of the visitors yield a non-null value. + * @param value The value to apply to the visitors. + * @return The first value found in the list of visitors after application of the given value, otherwise returns the + * given default. + */ + public static B nullableVisitor(final List> visitors, final P1 def, final A value) { + return visitor(visitors.map(new F, F>>() { + public F> f(final F k) { + return compose(Option.fromNull(), k); + } + }), def, value); + } + + /** + * Uses an association list to perform a lookup with equality and returns a function that can be applied to a default, + * followed by the associated key to return a value. + * + * @param x The association list. + * @param eq The equality for the association list keys. + * @return A function that can be applied to a default value (there is no association) and an associated key. + */ + public static F> association(final List> x, final Equal eq) { + return curry(new F2() { + public B f(final B def, final A a) { + return lookup(eq, x, a).orSome(def); + } + }); + } + + /** + * Uses an association list to perform a lookup with equality and returns a function that can be applied to a default, + * followed by the associated key to return a value. + * + * @param x The association list. + * @param eq The equality for the association list keys. + * @return A function that can be applied to a default value (there is no association) and an associated key. + */ + public static F, F> associationLazy(final List> x, final Equal eq) { + return curry(new F2, A, B>() { + public B f(final P1 def, final A a) { + return lookup(eq, x, a).orSome(def); + } + }); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/function/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/function/package-info.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,6 @@ +/** + * A prelude of commonly used first-class functions + * + * @version %build.number% + */ +package fj.function; diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/package-info.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,6 @@ +/** + * Types that set the premise for the existence of Functional Java. + * + * @version %build.number% + */ +package fj; diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/parser/Parser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/parser/Parser.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,1167 @@ +package fj.parser; + +import fj.F; +import static fj.P.p; +import fj.P1; +import fj.Semigroup; +import fj.Unit; +import fj.Digit; +import static fj.Unit.unit; +import fj.data.List; +import static fj.data.List.cons_; +import fj.data.Stream; +import fj.data.Validation; +import static fj.data.Validation.success; +import static fj.parser.Result.result; + +/** + * A parser is a function that takes some input (I) and produces either an error (E) or a parse result (A) and the + * remainder of the input. + * + * @version %build.number% + */ +public final class Parser { + private final F>> f; + + private Parser(final F>> f) { + this.f = f; + } + + /** + * Parses the input to produce a result or error. + * + * @param i The input to parse. + * @return A parse result with the remaining input or an error. + */ + public Validation> parse(final I i) { + return f.f(i); + } + + /** + * Maps the parse input type through an invariant functor. + * + * @param f The function to covariant map. + * @param g The function to contra-variant map. + * @return A parser with the new input type. + */ + public Parser xmap(final F f, final F g) { + return parser(new F>>() { + public Validation> f(final Z z) { + return parse(g.f(z)).map(new F, Result>() { + public Result f(final Result r) { + return r.mapRest(f); + } + }); + } + }); + } + + /** + * Maps the given result type across this parser. + * + * @param f The function to map. + * @return A parser with the new result type. + */ + public Parser map(final F f) { + return parser(new F>>() { + public Validation> f(final I i) { + return parse(i).map(new F, Result>() { + public Result f(final Result r) { + return r.mapValue(f); + } + }); + } + }); + } + + /** + * Returns a parser that fails with the given error if the result value does not meet the given predicate. + * + * @param f The predicate to filter on. + * @param e The error to in the event that the predicate is not met. + * @return A parser that fails with the given error if the result value does not meet the given predicate. + */ + public Parser filter(final F f, final E e) { + return parser(new F>>() { + public Validation> f(final I i) { + return parse(i).bind(new F, Validation>>() { + public Validation> f(final Result r) { + final A v = r.value(); + return f.f(v) ? + Validation.>success(result(r.rest(), v)) : + Validation.>fail(e); + } + }); + } + }); + } + + /** + * Binds the given function across the parser with a final join. + * + * @param f The function to apply to the element of this parser. + * @return A new parser after performing the map, then final join. + */ + public Parser bind(final F> f) { + return parser(new F>>() { + public Validation> f(final I i) { + return parse(i).bind(new F, Validation>>() { + public Validation> f(final Result r) { + return f.f(r.value()).parse(r.rest()); + } + }); + } + }); + } + + /** + * Binds the given function across the parsers with a final join. + * + * @param f The function to apply to the element of the parsers. + * @param pb A given parser to bind the given function with. + * @return A new parser after performing the map, then final join. + */ + public Parser bind(final Parser pb, final F> f) { + return pb.apply(map(f)); + } + + /** + * Binds the given function across the parsers with a final join. + * + * @param f The function to apply to the element of the parsers. + * @param pb A given parser to bind the given function with. + * @param pc A given parser to bind the given function with. + * @return A new parser after performing the map, then final join. + */ + public Parser bind(final Parser pb, final Parser pc, + final F>> f) { + return pc.apply(bind(pb, f)); + } + + /** + * Binds the given function across the parsers with a final join. + * + * @param f The function to apply to the element of the parsers. + * @param pb A given parser to bind the given function with. + * @param pc A given parser to bind the given function with. + * @param pd A given parser to bind the given function with. + * @return A new parser after performing the map, then final join. + */ + public Parser bind(final Parser pb, final Parser pc, + final Parser pd, final F>>> f) { + return pd.apply(bind(pb, pc, f)); + } + + /** + * Binds the given function across the parsers with a final join. + * + * @param f The function to apply to the element of the parsers. + * @param pb A given parser to bind the given function with. + * @param pc A given parser to bind the given function with. + * @param pd A given parser to bind the given function with. + * @param pe A given parser to bind the given function with. + * @return A new parser after performing the map, then final join. + */ + public Parser bind(final Parser pb, final Parser pc, + final Parser pd, final Parser pe, + final F>>>> f) { + return pe.apply(bind(pb, pc, pd, f)); + } + + /** + * Binds the given function across the parsers with a final join. + * + * @param f The function to apply to the element of the parsers. + * @param pb A given parser to bind the given function with. + * @param pc A given parser to bind the given function with. + * @param pd A given parser to bind the given function with. + * @param pe A given parser to bind the given function with. + * @param pf A given parser to bind the given function with. + * @return A new parser after performing the map, then final join. + */ + public Parser bind(final Parser pb, final Parser pc, + final Parser pd, final Parser pe, + final Parser pf, + final F>>>>> f) { + return pf.apply(bind(pb, pc, pd, pe, f)); + } + + /** + * Binds the given function across the parsers with a final join. + * + * @param f The function to apply to the element of the parsers. + * @param pb A given parser to bind the given function with. + * @param pc A given parser to bind the given function with. + * @param pd A given parser to bind the given function with. + * @param pe A given parser to bind the given function with. + * @param pf A given parser to bind the given function with. + * @param pg A given parser to bind the given function with. + * @return A new parser after performing the map, then final join. + */ + public Parser bind(final Parser pb, final Parser pc, + final Parser pd, final Parser pe, + final Parser pf, final Parser pg, + final F>>>>>> f) { + return pg.apply(bind(pb, pc, pd, pe, pf, f)); + } + + /** + * Binds the given function across the parsers with a final join. + * + * @param f The function to apply to the element of the parsers. + * @param pb A given parser to bind the given function with. + * @param pc A given parser to bind the given function with. + * @param pd A given parser to bind the given function with. + * @param pe A given parser to bind the given function with. + * @param pf A given parser to bind the given function with. + * @param pg A given parser to bind the given function with. + * @param ph A given parser to bind the given function with. + * @return A new parser after performing the map, then final join. + */ + public Parser bind(final Parser pb, final Parser pc, + final Parser pd, final Parser pe, + final Parser pf, final Parser pg, + final Parser ph, + final F>>>>>>> f) { + return ph.apply(bind(pb, pc, pd, pe, pf, pg, f)); + } + + /** + * Binds anonymously, ignoring the result value. + * + * @param p The parser to bind with. + * @return A parser after binding anonymously. + */ + public Parser sequence(final Parser p) { + return bind(new F>() { + public Parser f(final A a) { + return p; + } + }); + } + + /** + * Performs function application within a parser. + * + * @param p The parser returning a function value. + * @return A new parser after function application. + */ + public Parser apply(final Parser, E> p) { + return p.bind(new F, Parser>() { + public Parser f(final F f) { + return map(f); + } + }); + } + + /** + * Returns a parser that tries this parser and if it fails, then tries the given parser. + * + * @param alt The parser to try if this parser fails. + * @return A parser that tries this parser and if it fails, then tries the given parser. + */ + public Parser or(final P1> alt) { + return parser(new F>>() { + public Validation> f(final I i) { + return parse(i).f().sequence(alt._1().parse(i)); + } + }); + } + + /** + * Returns a parser that tries this parser and if it fails, then tries the given parser. + * + * @param alt The parser to try if this parser fails. + * @return A parser that tries this parser and if it fails, then tries the given parser. + */ + public Parser or(final Parser alt) { + return or(p(alt)); + } + + /** + * Returns a parser that tries this parser and if it fails, then tries the given parser. If both parsers fail, then + * append their errors with the given semigroup. + * + * @param alt The parser to try if this parser fails. + * @param s The semigroup to append error messages if both parsers fail. + * @return A parser that tries this parser and if it fails, then tries the given parser. + */ + public Parser or(final P1> alt, final Semigroup s) { + return parser(new F>>() { + public Validation> f(final I i) { + return parse(i).f().bind(new F>>() { + public Validation> f(final E e) { + return alt._1().parse(i).f().map(s.sum(e)); + } + }); + } + }); + } + + /** + * Returns a parser that tries this parser and if it fails, then tries the given parser. If both parsers fail, then + * append their errors with the given semigroup. + * + * @param alt The parser to try if this parser fails. + * @param s The semigroup to append error messages if both parsers fail. + * @return A parser that tries this parser and if it fails, then tries the given parser. + */ + public Parser or(final Parser alt, final Semigroup s) { + return or(p(alt), s); + } + + /** + * Returns a parser that negates this parser. If this parser succeeds, then the returned parser fails and vice versa. + * + * @param e The error message to fail with if this parser succeeds. + * @return A parser that negates this parser. + */ + public Parser not(final P1 e) { + return parser(new F>>() { + public Validation> f(final I i) { + return parse(i).isFail() ? + Validation.>success(result(i, unit())) : + Validation.>fail(e._1()); + } + }); + } + + /** + * Returns a parser that negates this parser. If this parser succeeds, then the returned parser fails and vice versa. + * + * @param e The error message to fail with if this parser succeeds. + * @return A parser that negates this parser. + */ + public Parser not(final E e) { + return not(p(e)); + } + + /** + * Returns a parser that repeats application of this parser zero or many times. + * + * @return A parser that repeats application of this parser zero or many times. + */ + public Parser, E> repeat() { + return repeat1().or(new P1, E>>() { + public Parser, E> _1() { + return value(Stream.nil()); + } + }); + } + + /** + * Returns a parser that repeats application of this parser one or many times. + * + * @return A parser that repeats application of this parser one or many times. + */ + public Parser, E> repeat1() { + return bind(new F, E>>() { + public Parser, E> f(final A a) { + return repeat().map(new F, Stream>() { + public Stream f(final Stream as) { + return as.cons(a); + } + }); + } + }); + } + + /** + * Maps the given function across this parser's error. + * + * @param f The function to map this parser's error with. + * @return A new parser with a new error type. + */ + public Parser mapError(final F f) { + return parser(new F>>() { + public Validation> f(final I i) { + return Parser.this.f.f(i).f().map(f); + } + }); + } + + /** + * Returns a parser that computes using the given function. + * + * @param f The function to construct the parser with. + * @return A parser that computes using the given function. + */ + public static Parser parser(final F>> f) { + return new Parser(f); + } + + /** + * Constructs a parser that always returns the given value. The unital for a parser. + * + * @param a The value to consistently return from a parser. + * @return A parser that always returns the given value. + */ + public static Parser value(final A a) { + return parser(new F>>() { + public Validation> f(final I i) { + return success(result(i, a)); + } + }); + } + + /** + * Returns a parser that always fails with the given error. + * + * @param e The error to fail with. + * @return A parser that always fails with the given error. + */ + public static Parser fail(final E e) { + return parser(new F>>() { + public Validation> f(final I i) { + return Validation.fail(e); + } + }); + } + + /** + * Sequence the list of parsers through {@link #bind}. + * + * @param ps The parsers to sequence. + * @return A parser after sequencing. + */ + public static Parser, E> sequence(final List> ps) { + return ps.isEmpty() ? + Parser., E>value(List.nil()) : + ps.head().bind(new F, E>>() { + public Parser, E> f(final A a) { + return sequence(ps.tail()).map(cons_(a)); + } + }); + } + + /** + * Parsers that accept {@link Stream} input. + */ + public static final class StreamParser { + private StreamParser() { + + } + + /** + * Returns a parser that produces an element from the stream if it is available and fails otherwise. + * + * @param e The error to fail with if no element is available. + * @return A parser that produces an element from the stream if it is available and fails otherwise. + */ + public static Parser, I, E> element(final P1 e) { + return parser(new F, Validation, I>>>() { + public Validation, I>> f(final Stream is) { + return is.isEmpty() ? + Validation., I>>fail(e._1()) : + Validation., I>>success(result(is.tail()._1(), is.head())); + } + }); + } + + /** + * Returns a parser that produces an element from the stream if it is available and fails otherwise. + * + * @param e The error to fail with if no element is available. + * @return A parser that produces an element from the stream if it is available and fails otherwise. + */ + public static Parser, I, E> element(final E e) { + return element(p(e)); + } + + /** + * Returns a parser that produces an element from the stream that satisfies the given predicate, or fails. + * + * @param missing The error if no element is available. + * @param sat The error if the element does not satisfy the predicate. + * @param f The predicate that the element should satisfy. + * @return A parser that produces an element from the stream that satisfies the given predicate, or fails. + */ + public static Parser, I, E> satisfy(final P1 missing, final F sat, + final F f) { + return StreamParser.element(missing).bind(new F, I, E>>() { + public Parser, I, E> f(final I x) { + return f.f(x) ? + Parser., I, E>value(x) : + Parser., I, E>fail(sat.f(x)); + } + }); + } + + /** + * Returns a parser that produces an element from the stream that satisfies the given predicate, or fails. + * + * @param missing The error if no element is available. + * @param sat The error if the element does not satisfy the predicate. + * @param f The predicate that the element should satisfy. + * @return A parser that produces an element from the stream that satisfies the given predicate, or fails. + */ + public static Parser, I, E> satisfy(final E missing, final F sat, final F f) { + return satisfy(p(missing), sat, f); + } + } + + /** + * Parsers that accept {@link Stream Stream<Character>} input. + */ + public static final class CharsParser { + private CharsParser() { + + } + + /** + * Returns a parser that produces a character if one is available or fails with the given error. + * + * @param e The error to fail with if a character is unavailable. + * @return A parser that produces a character if one is available or fails with the given error. + */ + public static Parser, Character, E> character(final P1 e) { + return StreamParser.element(e); + } + + /** + * Returns a parser that produces a character if one is available or fails with the given error. + * + * @param e The error to fail with if a character is unavailable. + * @return A parser that produces a character if one is available or fails with the given error. + */ + public static Parser, Character, E> character(final E e) { + return character(p(e)); + } + + /** + * Returns a parser that produces the given character or fails otherwise. + * + * @param missing The error if no character is available. + * @param sat The error if the produced character is not the one given. + * @param c The character to produce in the parser. + * @return A parser that produces the given character or fails otherwise. + */ + public static Parser, Character, E> character(final P1 missing, final F sat, + final char c) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character x) { + return x == c; + } + }); + } + + /** + * Returns a parser that produces the given character or fails otherwise. + * + * @param missing The error if no character is available. + * @param sat The error if the produced character is not the one given. + * @param c The character to produce in the parser. + * @return A parser that produces the given character or fails otherwise. + */ + public static Parser, Character, E> character(final E missing, final F sat, + final char c) { + return character(p(missing), sat, c); + } + + /** + * Returns a parser that produces the given number of characters, or fails with the given error. + * + * @param missing The error if the given number of characters is unavailable. + * @param n The number of characters to produce in the parse result. + * @return A parser that produces the given number of characters, or fails with the given error. + */ + public static Parser, Stream, E> characters(final P1 missing, final int n) { + return n <= 0 ? + Parser., Stream, E>value(Stream.nil()) : + character(missing).bind(characters(missing, n - 1), Stream.cons_()); + } + + /** + * Returns a parser that produces the given number of characters, or fails with the given error. + * + * @param missing The error if the given number of characters is unavailable. + * @param n The number of characters to produce in the parse result. + * @return A parser that produces the given number of characters, or fails with the given error. + */ + public static Parser, Stream, E> characters(final E missing, final int n) { + return characters(p(missing), n); + } + + /** + * Returns a parser that produces the given stream of characters or fails otherwise. + * + * @param missing The error if the producing stream could not supply more characters. + * @param sat The error if a character was produced that is not the given stream of characters. + * @param cs The stream of characters to produce. + * @return A parser that produces the given stream of characters or fails otherwise. + */ + public static Parser, Stream, E> characters(final P1 missing, + final F sat, + final Stream cs) { + return cs.isEmpty() ? + Parser., Stream, E>value(Stream.nil()) : + character(missing, sat, cs.head()).bind(characters(missing, sat, cs.tail()._1()), Stream.cons_()); + } + + /** + * Returns a parser that produces the given stream of characters or fails otherwise. + * + * @param missing The error if the producing stream could not supply more characters. + * @param sat The error if a character was produced that is not the given stream of characters. + * @param cs The stream of characters to produce. + * @return A parser that produces the given stream of characters or fails otherwise. + */ + public static Parser, Stream, E> characters(final E missing, + final F sat, + final Stream cs) { + return characters(p(missing), sat, cs); + } + + /** + * Returns a parser that produces the given string or fails otherwise. + * + * @param missing The error if the producing stream could not supply more characters. + * @param sat The error if a character was produced that is not the given string. + * @param s The string to produce. + * @return A parser that produces the given string or fails otherwise. + */ + public static Parser, String, E> string(final P1 missing, final F sat, + final String s) { + return characters(missing, sat, List.fromString(s).toStream()).map(new F, String>() { + public String f(final Stream cs) { + return List.asString(cs.toList()); + } + }); + } + + /** + * Returns a parser that produces the given string or fails otherwise. + * + * @param missing The error if the producing stream could not supply more characters. + * @param sat The error if a character was produced that is not the given string. + * @param s The string to produce. + * @return A parser that produces the given string or fails otherwise. + */ + public static Parser, String, E> string(final E missing, final F sat, + final String s) { + return string(p(missing), sat, s); + } + + /** + * Returns a parser that produces a digit (0 to 9). + * + * @param missing The error if there is no character on the stream to produce a digit with. + * @param sat The error if the produced character is not a digit. + * @return A parser that produces a digit (0 to 9). + */ + public static Parser, Digit, E> digit(final P1 missing, final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isDigit(c); + } + }).map(new F() { + public Digit f(final Character c) { + return Digit.fromChar(c).some(); + } + }); + } + + /** + * Returns a parser that produces a digit (0 to 9). + * + * @param missing The error if there is no character on the stream to produce a digit with. + * @param sat The error if the produced character is not a digit. + * @return A parser that produces a digit (0 to 9). + */ + public static Parser, Digit, E> digit(final E missing, final F sat) { + return digit(p(missing), sat); + } + + /** + * Returns a parser that produces a lower-case character. + * + * @param missing The error if there is no character on the stream to produce a lower-case character with. + * @param sat The error if the produced character is not a lower-case character. + * @return A parser that produces a lower-case character. + * @see Character#isLowerCase(char) + */ + public static Parser, Character, E> lower(final P1 missing, final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isLowerCase(c); + } + }); + } + + /** + * Returns a parser that produces a lower-case character. + * + * @param missing The error if there is no character on the stream to produce a lower-case character with. + * @param sat The error if the produced character is not a lower-case character. + * @return A parser that produces a lower-case character. + * @see Character#isLowerCase(char) + */ + public static Parser, Character, E> lower(final E missing, final F sat) { + return lower(p(missing), sat); + } + + /** + * Returns a parser that produces a upper-case character. + * + * @param missing The error if there is no character on the stream to produce a upper-case character with. + * @param sat The error if the produced character is not a upper-case character. + * @return A parser that produces a upper-case character. + * @see Character#isUpperCase(char) + */ + public static Parser, Character, E> upper(final P1 missing, final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isUpperCase(c); + } + }); + } + + /** + * Returns a parser that produces a upper-case character. + * + * @param missing The error if there is no character on the stream to produce a upper-case character with. + * @param sat The error if the produced character is not a upper-case character. + * @return A parser that produces a upper-case character. + * @see Character#isUpperCase(char) + */ + public static Parser, Character, E> upper(final E missing, final F sat) { + return upper(p(missing), sat); + } + + /** + * Returns a parser that produces a defined character. + * + * @param missing The error if there is no character on the stream to produce a defined character with. + * @param sat The error if the produced character is not a defined character. + * @return A parser that produces a defined character. + * @see Character#isDefined(char) + */ + public static Parser, Character, E> defined(final P1 missing, final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isDefined(c); + } + }); + } + + /** + * Returns a parser that produces a defined character. + * + * @param missing The error if there is no character on the stream to produce a defined character with. + * @param sat The error if the produced character is not a defined character. + * @return A parser that produces a defined character. + * @see Character#isDefined(char) + */ + public static Parser, Character, E> defined(final E missing, final F sat) { + return defined(p(missing), sat); + } + + /** + * Returns a parser that produces a high-surrogate character. + * + * @param missing The error if there is no character on the stream to produce a high-surrogate character with. + * @param sat The error if the produced character is not a high-surrogate character. + * @return A parser that produces a high-surrogate character. + * @see Character#isHighSurrogate(char) + */ + public static Parser, Character, E> highSurrogate(final P1 missing, + final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isHighSurrogate(c); + } + }); + } + + /** + * Returns a parser that produces a high-surrogate character. + * + * @param missing The error if there is no character on the stream to produce a high-surrogate character with. + * @param sat The error if the produced character is not a high-surrogate character. + * @return A parser that produces a high-surrogate character. + * @see Character#isHighSurrogate(char) + */ + public static Parser, Character, E> highSurrogate(final E missing, + final F sat) { + return highSurrogate(p(missing), sat); + } + + /** + * Returns a parser that produces an identifier-ignorable character. + * + * @param missing The error if there is no character on the stream to produce an identifier-ignorable character with. + * @param sat The error if the produced character is not an identifier-ignorable character. + * @return A parser that produces an identifier-ignorable character. + * @see Character#isIdentifierIgnorable(char) + */ + public static Parser, Character, E> identifierIgnorable(final P1 missing, + final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isIdentifierIgnorable(c); + } + }); + } + + /** + * Returns a parser that produces an identifier-ignorable character. + * + * @param missing The error if there is no character on the stream to produce an identifier-ignorable character with. + * @param sat The error if the produced character is not an identifier-ignorable character. + * @return A parser that produces an identifier-ignorable character. + * @see Character#isIdentifierIgnorable(char) + */ + public static Parser, Character, E> identifierIgnorable(final E missing, + final F sat) { + return identifierIgnorable(p(missing), sat); + } + + /** + * Returns a parser that produces an ISO control character. + * + * @param missing The error if there is no character on the stream to produce an ISO control character with. + * @param sat The error if the produced character is not an ISO control character. + * @return A parser that produces an ISO control character. + * @see Character#isISOControl(char) + */ + public static Parser, Character, E> isoControl(final P1 missing, + final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isISOControl(c); + } + }); + } + + /** + * Returns a parser that produces an ISO control character. + * + * @param missing The error if there is no character on the stream to produce an ISO control character with. + * @param sat The error if the produced character is not an ISO control character. + * @return A parser that produces an ISO control character. + * @see Character#isISOControl(char) + */ + public static Parser, Character, E> isoControl(final E missing, final F sat) { + return isoControl(p(missing), sat); + } + + /** + * Returns a parser that produces a Java identifier part character. + * + * @param missing The error if there is no character on the stream to produce a Java identifier part character with. + * @param sat The error if the produced character is not a Java identifier part character. + * @return A parser that produces a Java identifier part character. + * @see Character#isJavaIdentifierPart(char) + */ + public static Parser, Character, E> javaIdentifierPart(final P1 missing, + final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isJavaIdentifierPart(c); + } + }); + } + + /** + * Returns a parser that produces a Java identifier part character. + * + * @param missing The error if there is no character on the stream to produce a Java identifier part character with. + * @param sat The error if the produced character is not a Java identifier part character. + * @return A parser that produces a Java identifier part character. + * @see Character#isJavaIdentifierPart(char) + */ + public static Parser, Character, E> javaIdentifierPart(final E missing, + final F sat) { + return javaIdentifierPart(p(missing), sat); + } + + /** + * Returns a parser that produces a Java identifier start character. + * + * @param missing The error if there is no character on the stream to produce a Java identifier start character with. + * @param sat The error if the produced character is not a Java identifier start character. + * @return A parser that produces a Java identifier start character. + * @see Character#isJavaIdentifierStart(char) + */ + public static Parser, Character, E> javaIdentifierStart(final P1 missing, + final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isJavaIdentifierStart(c); + } + }); + } + + /** + * Returns a parser that produces a Java identifier start character. + * + * @param missing The error if there is no character on the stream to produce a Java identifier start character with. + * @param sat The error if the produced character is not a Java identifier start character. + * @return A parser that produces a Java identifier start character. + * @see Character#isJavaIdentifierStart(char) + */ + public static Parser, Character, E> javaIdentifierStart(final E missing, + final F sat) { + return javaIdentifierStart(p(missing), sat); + } + + /** + * Returns a parser that produces an alpha character. + * + * @param missing The error if there is no character on the stream to produce an alpha character with. + * @param sat The error if the produced character is not an alpha character. + * @return A parser that produces an alpha character. + * @see Character#isLetter(char) + */ + public static Parser, Character, E> alpha(final P1 missing, final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isLetter(c); + } + }); + } + + /** + * Returns a parser that produces an alpha character. + * + * @param missing The error if there is no character on the stream to produce an alpha character with. + * @param sat The error if the produced character is not an alpha character. + * @return A parser that produces an alpha character. + * @see Character#isLetter(char) + */ + public static Parser, Character, E> alpha(final E missing, final F sat) { + return alpha(p(missing), sat); + } + + /** + * Returns a parser that produces an alpha-numeric character. + * + * @param missing The error if there is no character on the stream to produce an alpha-numeric character with. + * @param sat The error if the produced character is not an alpha-numeric character. + * @return A parser that produces an alpha-numeric character. + * @see Character#isLetterOrDigit(char) + */ + public static Parser, Character, E> alphaNum(final P1 missing, final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isLetterOrDigit(c); + } + }); + } + + /** + * Returns a parser that produces an alpha-numeric character. + * + * @param missing The error if there is no character on the stream to produce an alpha-numeric character with. + * @param sat The error if the produced character is not an alpha-numeric character. + * @return A parser that produces an alpha-numeric character. + * @see Character#isLetterOrDigit(char) + */ + public static Parser, Character, E> alphaNum(final E missing, final F sat) { + return alphaNum(p(missing), sat); + } + + /** + * Returns a parser that produces a low-surrogate character. + * + * @param missing The error if there is no character on the stream to produce a low-surrogate character with. + * @param sat The error if the produced character is not a low-surrogate character. + * @return A parser that produces a low-surrogate character. + * @see Character#isLowSurrogate(char) + */ + public static Parser, Character, E> lowSurrogate(final P1 missing, + final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isLowSurrogate(c); + } + }); + } + + /** + * Returns a parser that produces a low-surrogate character. + * + * @param missing The error if there is no character on the stream to produce a low-surrogate character with. + * @param sat The error if the produced character is not a low-surrogate character. + * @return A parser that produces a low-surrogate character. + * @see Character#isLowSurrogate(char) + */ + public static Parser, Character, E> lowSurrogate(final E missing, final F sat) { + return lowSurrogate(p(missing), sat); + } + + /** + * Returns a parser that produces a mirrored character. + * + * @param missing The error if there is no character on the stream to produce a mirrored character with. + * @param sat The error if the produced character is not a mirrored character. + * @return A parser that produces a mirrored character. + * @see Character#isMirrored(char) + */ + public static Parser, Character, E> mirrored(final P1 missing, final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isMirrored(c); + } + }); + } + + /** + * Returns a parser that produces a mirrored character. + * + * @param missing The error if there is no character on the stream to produce a mirrored character with. + * @param sat The error if the produced character is not a mirrored character. + * @return A parser that produces a mirrored character. + * @see Character#isMirrored(char) + */ + public static Parser, Character, E> mirrored(final E missing, final F sat) { + return mirrored(p(missing), sat); + } + + /** + * Returns a parser that produces a space character. + * + * @param missing The error if there is no character on the stream to produce a space character with. + * @param sat The error if the produced character is not a space character. + * @return A parser that produces a space character. + * @see Character#isSpace(char) + */ + public static Parser, Character, E> space(final P1 missing, final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isSpaceChar(c); + } + }); + } + + /** + * Returns a parser that produces a space character. + * + * @param missing The error if there is no character on the stream to produce a space character with. + * @param sat The error if the produced character is not a space character. + * @return A parser that produces a space character. + * @see Character#isSpace(char) + */ + public static Parser, Character, E> space(final E missing, final F sat) { + return space(p(missing), sat); + } + + /** + * Returns a parser that produces a title-case character. + * + * @param missing The error if there is no character on the stream to produce a title-case character with. + * @param sat The error if the produced character is not a title-case character. + * @return A parser that produces a title-case character. + * @see Character#isTitleCase(char) + */ + public static Parser, Character, E> titleCase(final P1 missing, + final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isTitleCase(c); + } + }); + } + + /** + * Returns a parser that produces a title-case character. + * + * @param missing The error if there is no character on the stream to produce a title-case character with. + * @param sat The error if the produced character is not a title-case character. + * @return A parser that produces a title-case character. + * @see Character#isTitleCase(char) + */ + public static Parser, Character, E> titleCase(final E missing, final F sat) { + return titleCase(p(missing), sat); + } + + /** + * Returns a parser that produces a unicode identifier part character. + * + * @param missing The error if there is no character on the stream to produce a unicode identifier part character with. + * @param sat The error if the produced character is not a unicode identifier part character. + * @return A parser that produces a unicode identifier part character. + * @see Character#isUnicodeIdentifierPart(char) + */ + public static Parser, Character, E> unicodeIdentiferPart(final P1 missing, + final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isUnicodeIdentifierPart(c); + } + }); + } + + /** + * Returns a parser that produces a unicode identifier part character. + * + * @param missing The error if there is no character on the stream to produce a unicode identifier part character with. + * @param sat The error if the produced character is not a unicode identifier part character. + * @return A parser that produces a unicode identifier part character. + * @see Character#isUnicodeIdentifierPart(char) + */ + public static Parser, Character, E> unicodeIdentiferPart(final E missing, + final F sat) { + return unicodeIdentiferPart(p(missing), sat); + } + + /** + * Returns a parser that produces a unicode identifier start character. + * + * @param missing The error if there is no character on the stream to produce a unicode identifier start character with. + * @param sat The error if the produced character is not a unicode identifier start character. + * @return A parser that produces a unicode identifier start character. + * @see Character#isUnicodeIdentifierStart(char) + */ + public static Parser, Character, E> unicodeIdentiferStart(final P1 missing, + final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isUnicodeIdentifierStart(c); + } + }); + } + + /** + * Returns a parser that produces a unicode identifier start character. + * + * @param missing The error if there is no character on the stream to produce a unicode identifier start character with. + * @param sat The error if the produced character is not a unicode identifier start character. + * @return A parser that produces a unicode identifier start character. + * @see Character#isUnicodeIdentifierStart(char) + */ + public static Parser, Character, E> unicodeIdentiferStart(final E missing, + final F sat) { + return unicodeIdentiferStart(p(missing), sat); + } + + /** + * Returns a parser that produces a white-space character. + * + * @param missing The error if there is no character on the stream to produce a white-space character with. + * @param sat The error if the produced character is not a white-space character. + * @return A parser that produces a white-space character. + * @see Character#isWhitespace(char) + */ + public static Parser, Character, E> whitespace(final P1 missing, + final F sat) { + return StreamParser.satisfy(missing, sat, new F() { + public Boolean f(final Character c) { + return Character.isWhitespace(c); + } + }); + } + + /** + * Returns a parser that produces a white-space character. + * + * @param missing The error if there is no character on the stream to produce a white-space character with. + * @param sat The error if the produced character is not a white-space character. + * @return A parser that produces a white-space character. + * @see Character#isWhitespace(char) + */ + public static Parser, Character, E> whitespace(final E missing, final F sat) { + return whitespace(p(missing), sat); + } + } +} \ No newline at end of file diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/parser/Result.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/parser/Result.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,163 @@ +package fj.parser; + +import fj.F; +import fj.F2; +import static fj.Function.curry; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * A parse result made up of a value (A) and the remainder of the parse input (I). + * + * @version %build.number% + */ +public final class Result implements Iterable { + private final I i; + private final A a; + + private Result(final I i, final A a) { + this.i = i; + this.a = a; + } + + /** + * The remainder of the parse input. + * + * @return The remainder of the parse input. + */ + public I rest() { + return i; + } + + /** + * The parsed value. + * + * @return The parsed value. + */ + public A value() { + return a; + } + + /** + * Maps the given function across the remainder of the parse input. + * + * @param f The function to map with. + * @return A result with a different parse input. + */ + public Result mapRest(final F f) { + return result(f.f(i), a); + } + + /** + * First-class function mapping across the remainder of the parse input. + * + * @return A first-class function mapping across the remainder of the parse input. + */ + public F, Result> mapRest() { + return new F, Result>() { + public Result f(final F f) { + return mapRest(f); + } + }; + } + + /** + * Maps the given function across the parse value. + * + * @param f The function to map with. + * @return A result with a different parse value. + */ + public Result mapValue(final F f) { + return result(i, f.f(a)); + } + + /** + * First-class function mapping across the parse value. + * + * @return A first-class function mapping across the parse value. + */ + public F, Result> mapValue() { + return new F, Result>() { + public Result f(final F f) { + return mapValue(f); + } + }; + } + + /** + * A bifunctor map across both the remainder of the parse input and the parse value. + * + * @param f The function to map the remainder of the parse input with. + * @param g The function to map the parse value with. + * @return A result with a different parse input and parse value. + */ + public Result bimap(final F f, final F g) { + return mapRest(f).mapValue(g); + } + + /** + * First-class bifunctor map. + * + * @return A first-class bifunctor map. + */ + public F, F, Result>> bimap() { + return curry(new F2, F, Result>() { + public Result f(final F f, final F g) { + return bimap(f, g); + } + }); + } + + /** + * Returns an iterator over the parse value. This method exists to permit the use in a for-each loop. + * + * @return An iterator over the parse value. + */ + public Iterator iterator() { + return new Iterator() { + private boolean r; + + public boolean hasNext() { + return !r; + } + + public A next() { + if (r) + throw new NoSuchElementException(); + else { + r = true; + return a; + } + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + /** + * Construct a result with the given remainder of the parse input and parse value. + * + * @param i The remainder of the parse input. + * @param a The parse value. + * @return A result with the given remainder of the parse input and parse value. + */ + public static Result result(final I i, final A a) { + return new Result(i, a); + } + + /** + * First-class construction of a result. + * + * @return A first-class function for construction of a result. + */ + public static F>> result() { + return curry(new F2>() { + public Result f(final I i, final A a) { + return result(i, a); + } + }); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/parser/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/parser/package-info.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,6 @@ +/** + * Parser combinators. + * + * @version %build.number% + */ +package fj.parser; diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/Arbitrary.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/Arbitrary.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,1672 @@ +package fj.test; + +import fj.F; +import fj.F2; +import fj.F3; +import fj.F4; +import fj.F5; +import fj.F6; +import fj.F7; +import fj.F8; +import fj.Function; +import static fj.Function.compose; +import static fj.P.p; +import fj.P1; +import fj.P2; +import fj.P3; +import fj.P4; +import fj.P5; +import fj.P6; +import fj.P7; +import fj.P8; +import fj.data.*; +import fj.LcgRng; + +import static fj.data.Either.left; +import static fj.data.Either.right; +import static fj.data.Enumerator.charEnumerator; +import static fj.data.List.asString; +import static fj.data.List.list; +import static fj.data.Option.some; + +import fj.function.Effect1; + +import static fj.data.Stream.range; +import static fj.test.Gen.choose; +import static fj.test.Gen.elements; +import static fj.test.Gen.fail; +import static fj.test.Gen.frequency; +import static fj.test.Gen.listOf; +import static fj.test.Gen.oneOf; +import static fj.test.Gen.promote; +import static fj.test.Gen.sized; +import static fj.test.Gen.value; + +import static java.lang.Math.abs; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Calendar; +import java.util.Date; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.Locale; +import static java.util.Locale.getAvailableLocales; +import java.util.PriorityQueue; +import java.util.Properties; +import java.util.Stack; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.Vector; +import java.util.WeakHashMap; +import static java.util.EnumSet.copyOf; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Delayed; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.SynchronousQueue; + +/** + * The type used to generate arbitrary values of the given type parameter (A). Common + * arbitrary implementations are provided. + * + * @version %build.number% + */ +public final class Arbitrary { + /** + * The generator associated with this arbitrary. + */ + @SuppressWarnings({"PublicField"}) + public final Gen gen; + + private Arbitrary(final Gen gen) { + this.gen = gen; + } + + /** + * Constructs and arbitrary with the given generator. + * + * @param g The generator to construct an arbitrary with. + * @return A new arbitrary that uses the given generator. + */ + public static Arbitrary arbitrary(final Gen g) { + return new Arbitrary(g); + } + + /** + * An arbitrary for functions. + * + * @param c The coarbitrary for the function domain. + * @param a The arbitrary for the function codomain. + * @return An arbitrary for functions. + */ + public static Arbitrary> arbF(final Coarbitrary c, final Arbitrary a) { + return arbitrary(promote(new F>() { + public Gen f(final A x) { + return c.coarbitrary(x, a.gen); + } + })); + } + + public static Arbitrary> arbReader(Coarbitrary aa, Arbitrary ab) { + return arbitrary(Arbitrary.arbF(aa, ab).gen.map(f -> Reader.unit(f))); + } + + /** + * An arbitrary for state. + */ + public static Arbitrary> arbState(Arbitrary as, Coarbitrary cs, Arbitrary aa) { + return arbitrary(arbF(cs, arbP2(as, aa)).gen.map(f -> State.unit(f))); + } + + /** + * An arbitrary for the LcgRng. + */ + public static Arbitrary arbLcgRng() { + return arbitrary(Arbitrary.arbLong.gen.map(l -> new LcgRng(l))); + } + + /** + * An arbitrary for functions. + * + * @param a The arbitrary for the function codomain. + * @return An arbitrary for functions. + */ + public static Arbitrary> arbFInvariant(final Arbitrary a) { + return arbitrary(a.gen.map(Function.constant())); + } + + /** + * An arbitrary for function-2. + * + * @param ca A coarbitrary for the part of the domain of the function. + * @param cb A coarbitrary for the part of the domain of the function. + * @param a An arbitrary for the codomain of the function. + * @return An arbitrary for function-2. + */ + public static Arbitrary> arbF2(final Coarbitrary ca, final Coarbitrary cb, + final Arbitrary a) { + return arbitrary(arbF(ca, arbF(cb, a)).gen.map(Function.uncurryF2())); + } + + /** + * An arbitrary for function-2. + * + * @param a The arbitrary for the function codomain. + * @return An arbitrary for function-2. + */ + public static Arbitrary> arbF2Invariant(final Arbitrary a) { + return arbitrary(a.gen.map( + compose(Function.uncurryF2(), compose(Function.>constant(), Function.constant())))); + } + + /** + * An arbitrary for function-3. + * + * @param ca A coarbitrary for the part of the domain of the function. + * @param cb A coarbitrary for the part of the domain of the function. + * @param cc A coarbitrary for the part of the domain of the function. + * @param a An arbitrary for the codomain of the function. + * @return An arbitrary for function-3. + */ + public static Arbitrary> arbF3(final Coarbitrary ca, final Coarbitrary cb, + final Coarbitrary cc, final Arbitrary a) { + return arbitrary(arbF(ca, arbF(cb, arbF(cc, a))).gen.map(Function.uncurryF3())); + } + + /** + * An arbitrary for function-3. + * + * @param a The arbitrary for the function codomain. + * @return An arbitrary for function-3. + */ + public static Arbitrary> arbF3Invariant(final Arbitrary a) { + return arbitrary(a.gen.map(compose(Function.uncurryF3(), compose(Function.>>constant(), + compose( + Function.>constant(), + Function.constant()))))); + } + + /** + * An arbitrary for function-4. + * + * @param ca A coarbitrary for the part of the domain of the function. + * @param cb A coarbitrary for the part of the domain of the function. + * @param cc A coarbitrary for the part of the domain of the function. + * @param cd A coarbitrary for the part of the domain of the function. + * @param a An arbitrary for the codomain of the function. + * @return An arbitrary for function-4. + */ + public static Arbitrary> arbF4(final Coarbitrary ca, final Coarbitrary cb, + final Coarbitrary cc, final Coarbitrary cd, + final Arbitrary a) { + return arbitrary(arbF(ca, arbF(cb, arbF(cc, arbF(cd, a)))).gen.map(Function.uncurryF4())); + } + + /** + * An arbitrary for function-4. + * + * @param a The arbitrary for the function codomain. + * @return An arbitrary for function-4. + */ + public static Arbitrary> arbF4Invariant(final Arbitrary a) { + return arbitrary(a.gen.map(compose(Function.uncurryF4(), + compose(Function.>>>constant(), + compose(Function.>>constant(), + compose(Function.>constant(), + Function.constant())))))); + } + + /** + * An arbitrary for function-5. + * + * @param ca A coarbitrary for the part of the domain of the function. + * @param cb A coarbitrary for the part of the domain of the function. + * @param cc A coarbitrary for the part of the domain of the function. + * @param cd A coarbitrary for the part of the domain of the function. + * @param ce A coarbitrary for the part of the domain of the function. + * @param a An arbitrary for the codomain of the function. + * @return An arbitrary for function-5. + */ + public static Arbitrary> arbF5(final Coarbitrary ca, + final Coarbitrary cb, + final Coarbitrary cc, + final Coarbitrary cd, + final Coarbitrary ce, + final Arbitrary a) { + return arbitrary( + arbF(ca, arbF(cb, arbF(cc, arbF(cd, arbF(ce, a))))).gen.map(Function.uncurryF5())); + } + + /** + * An arbitrary for function-5. + * + * @param a The arbitrary for the function codomain. + * @return An arbitrary for function-5. + */ + public static Arbitrary> arbF5Invariant(final Arbitrary a) { + return arbitrary(a.gen.map(compose(Function.uncurryF5(), + compose(Function.>>>>constant(), + compose(Function.>>>constant(), + compose(Function.>>constant(), + compose(Function.>constant(), + Function.constant()))))))); + } + + /** + * An arbitrary for function-6. + * + * @param ca A coarbitrary for the part of the domain of the function. + * @param cb A coarbitrary for the part of the domain of the function. + * @param cc A coarbitrary for the part of the domain of the function. + * @param cd A coarbitrary for the part of the domain of the function. + * @param ce A coarbitrary for the part of the domain of the function. + * @param cf A coarbitrary for the part of the domain of the function. + * @param a An arbitrary for the codomain of the function. + * @return An arbitrary for function-6. + */ + public static Arbitrary> arbF6(final Coarbitrary ca, + final Coarbitrary cb, + final Coarbitrary cc, + final Coarbitrary cd, + final Coarbitrary ce, + final Coarbitrary cf, + final Arbitrary a) { + return arbitrary(arbF(ca, arbF(cb, arbF(cc, arbF(cd, arbF(ce, arbF(cf, a)))))).gen.map( + Function.uncurryF6())); + } + + /** + * An arbitrary for function-6. + * + * @param a The arbitrary for the function codomain. + * @return An arbitrary for function-6. + */ + public static Arbitrary> arbF6Invariant(final Arbitrary a) { + return arbitrary(a.gen.map(compose(Function.uncurryF6(), + compose(Function.>>>>>constant(), + compose(Function.>>>>constant(), + compose(Function.>>>constant(), + compose(Function.>>constant(), + compose(Function.>constant(), + Function.constant())))))))); + } + + /** + * An arbitrary for function-7. + * + * @param ca A coarbitrary for the part of the domain of the function. + * @param cb A coarbitrary for the part of the domain of the function. + * @param cc A coarbitrary for the part of the domain of the function. + * @param cd A coarbitrary for the part of the domain of the function. + * @param ce A coarbitrary for the part of the domain of the function. + * @param cf A coarbitrary for the part of the domain of the function. + * @param cg A coarbitrary for the part of the domain of the function. + * @param a An arbitrary for the codomain of the function. + * @return An arbitrary for function-7. + */ + public static Arbitrary> arbF7(final Coarbitrary ca, + final Coarbitrary cb, + final Coarbitrary cc, + final Coarbitrary cd, + final Coarbitrary ce, + final Coarbitrary cf, + final Coarbitrary cg, + final Arbitrary a) { + return arbitrary(arbF(ca, arbF(cb, arbF(cc, arbF(cd, arbF(ce, arbF(cf, arbF(cg, a))))))).gen.map( + Function.uncurryF7())); + } + + /** + * An arbitrary for function-7. + * + * @param a The arbitrary for the function codomain. + * @return An arbitrary for function-7. + */ + public static Arbitrary> arbF7Invariant(final Arbitrary a) { + return arbitrary(a.gen.map(compose(Function.uncurryF7(), + compose(Function.>>>>>>constant(), + compose(Function.>>>>>constant(), + compose(Function.>>>>constant(), + compose(Function.>>>constant(), + compose(Function.>>constant(), + compose(Function.>constant(), + Function.constant()))))))))); + } + + /** + * An arbitrary for function-8. + * + * @param ca A coarbitrary for the part of the domain of the function. + * @param cb A coarbitrary for the part of the domain of the function. + * @param cc A coarbitrary for the part of the domain of the function. + * @param cd A coarbitrary for the part of the domain of the function. + * @param ce A coarbitrary for the part of the domain of the function. + * @param cf A coarbitrary for the part of the domain of the function. + * @param cg A coarbitrary for the part of the domain of the function. + * @param ch A coarbitrary for the part of the domain of the function. + * @param a An arbitrary for the codomain of the function. + * @return An arbitrary for function-8. + */ + public static Arbitrary> arbF8(final Coarbitrary ca, + final Coarbitrary cb, + final Coarbitrary cc, + final Coarbitrary cd, + final Coarbitrary ce, + final Coarbitrary cf, + final Coarbitrary cg, + final Coarbitrary ch, + final Arbitrary a) { + return arbitrary(arbF(ca, arbF(cb, arbF(cc, arbF(cd, arbF(ce, arbF(cf, arbF(cg, arbF(ch, a)))))))).gen.map( + Function.uncurryF8())); + } + + /** + * An arbitrary for function-8. + * + * @param a The arbitrary for the function codomain. + * @return An arbitrary for function-8. + */ + public static Arbitrary> arbF8Invariant( + final Arbitrary a) { + return arbitrary(a.gen.map(compose(Function.uncurryF8(), + compose(Function.>>>>>>>constant(), + compose(Function.>>>>>>constant(), + compose(Function.>>>>>constant(), + compose( + Function.>>>>constant(), + compose(Function.>>>constant(), + compose( + Function.>>constant(), + compose(Function.>constant(), + Function.constant())))))))))); + } + + /** + * An arbitrary implementation for boolean values. + */ + public static final Arbitrary arbBoolean = arbitrary(elements(true, false)); + + /** + * An arbitrary implementation for integer values. + */ + public static final Arbitrary arbInteger = arbitrary(sized(new F>() { + public Gen f(final Integer i) { + return choose(-i, i); + } + })); + + /** + * An arbitrary implementation for integer values that checks boundary values (0, 1, -1, + * max, min, max - 1, min + 1) with a frequency of 1% each then generates from {@link + * #arbInteger} the remainder of the time (93%). + */ + public static final Arbitrary arbIntegerBoundaries = arbitrary(sized(new F>() { + @SuppressWarnings("unchecked") + public Gen f(final Integer i) { + return frequency(list(p(1, value(0)), + p(1, value(1)), + p(1, value(-1)), + p(1, value(Integer.MAX_VALUE)), + p(1, value(Integer.MIN_VALUE)), + p(1, value(Integer.MAX_VALUE - 1)), + p(1, value(Integer.MIN_VALUE + 1)), + p(93, arbInteger.gen))); + } + })); + + /** + * An arbitrary implementation for long values. + */ + public static final Arbitrary arbLong = + arbitrary(arbInteger.gen.bind(arbInteger.gen, new F>() { + public F f(final Integer i1) { + return new F() { + public Long f(final Integer i2) { + return (long) i1 << 32L & i2; + } + }; + } + })); + + /** + * An arbitrary implementation for long values that checks boundary values (0, 1, -1, max, + * min, max - 1, min + 1) with a frequency of 1% each then generates from {@link #arbLong} + * the remainder of the time (93%). + */ + public static final Arbitrary arbLongBoundaries = arbitrary(sized(new F>() { + @SuppressWarnings("unchecked") + public Gen f(final Integer i) { + return frequency(list(p(1, value(0L)), + p(1, value(1L)), + p(1, value(-1L)), + p(1, value(Long.MAX_VALUE)), + p(1, value(Long.MIN_VALUE)), + p(1, value(Long.MAX_VALUE - 1L)), + p(1, value(Long.MIN_VALUE + 1L)), + p(93, arbLong.gen))); + } + })); + + /** + * An arbitrary implementation for byte values. + */ + public static final Arbitrary arbByte = arbitrary(arbInteger.gen.map(new F() { + public Byte f(final Integer i) { + return (byte) i.intValue(); + } + })); + + /** + * An arbitrary implementation for byte values that checks boundary values (0, 1, -1, max, + * min, max - 1, min + 1) with a frequency of 1% each then generates from {@link #arbByte} + * the remainder of the time (93%). + */ + public static final Arbitrary arbByteBoundaries = arbitrary(sized(new F>() { + @SuppressWarnings("unchecked") + public Gen f(final Integer i) { + return frequency(list(p(1, value((byte) 0)), + p(1, value((byte) 1)), + p(1, value((byte) -1)), + p(1, value(Byte.MAX_VALUE)), + p(1, value(Byte.MIN_VALUE)), + p(1, value((byte) (Byte.MAX_VALUE - 1))), + p(1, value((byte) (Byte.MIN_VALUE + 1))), + p(93, arbByte.gen))); + } + })); + + /** + * An arbitrary implementation for short values. + */ + public static final Arbitrary arbShort = arbitrary(arbInteger.gen.map(new F() { + public Short f(final Integer i) { + return (short) i.intValue(); + } + })); + + /** + * An arbitrary implementation for short values that checks boundary values (0, 1, -1, max, + * min, max - 1, min + 1) with a frequency of 1% each then generates from {@link #arbShort} + * the remainder of the time (93%). + */ + public static final Arbitrary arbShortBoundaries = arbitrary(sized(new F>() { + @SuppressWarnings("unchecked") + public Gen f(final Integer i) { + return frequency(list(p(1, value((short) 0)), + p(1, value((short) 1)), + p(1, value((short) -1)), + p(1, value(Short.MAX_VALUE)), + p(1, value(Short.MIN_VALUE)), + p(1, value((short) (Short.MAX_VALUE - 1))), + p(1, value((short) (Short.MIN_VALUE + 1))), + p(93, arbShort.gen))); + } + })); + + /** + * An arbitrary implementation for character values. + */ + public static final Arbitrary arbCharacter = arbitrary(choose(0, 65536).map(new F() { + public Character f(final Integer i) { + return (char) i.intValue(); + } + })); + + /** + * An arbitrary implementation for character values that checks boundary values (max, min, + * max - 1, min + 1) with a frequency of 1% each then generates from {@link #arbCharacter} + * the remainder of the time (96%). + */ + public static final Arbitrary arbCharacterBoundaries = arbitrary(sized(new F>() { + @SuppressWarnings("unchecked") + public Gen f(final Integer i) { + return frequency(list(p(1, value(Character.MIN_VALUE)), + p(1, value((char) (Character.MIN_VALUE + 1))), + p(1, value(Character.MAX_VALUE)), + p(1, value((char) (Character.MAX_VALUE - 1))), + p(95, arbCharacter.gen))); + } + })); + + /** + * An arbitrary implementation for double values. + */ + public static final Arbitrary arbDouble = arbitrary(sized(new F>() { + public Gen f(final Integer i) { + return choose((double) -i, i); + } + })); + + /** + * An arbitrary implementation for double values that checks boundary values (0, 1, -1, max, + * min, min (normal), NaN, -infinity, infinity, max - 1) with a frequency of 1% each then + * generates from {@link #arbDouble} the remainder of the time (91%). + */ + public static final Arbitrary arbDoubleBoundaries = arbitrary(sized(new F>() { + @SuppressWarnings("unchecked") + public Gen f(final Integer i) { + return frequency(list(p(1, value(0D)), + p(1, value(1D)), + p(1, value(-1D)), + p(1, value(Double.MAX_VALUE)), + p(1, value(Double.MIN_VALUE)), + p(1, value(Double.NaN)), + p(1, value(Double.NEGATIVE_INFINITY)), + p(1, value(Double.POSITIVE_INFINITY)), + p(1, value(Double.MAX_VALUE - 1D)), + p(91, arbDouble.gen))); + } + })); + + /** + * An arbitrary implementation for float values. + */ + public static final Arbitrary arbFloat = arbitrary(arbDouble.gen.map(new F() { + public Float f(final Double d) { + return (float) d.doubleValue(); + } + })); + + /** + * An arbitrary implementation for float values that checks boundary values (0, 1, -1, max, + * min, NaN, -infinity, infinity, max - 1) with a frequency of 1% each then generates from + * {@link #arbFloat} the remainder of the time (91%). + */ + public static final Arbitrary arbFloatBoundaries = arbitrary(sized(new F>() { + @SuppressWarnings("unchecked") + public Gen f(final Integer i) { + return frequency(list(p(1, value(0F)), + p(1, value(1F)), + p(1, value(-1F)), + p(1, value(Float.MAX_VALUE)), + p(1, value(Float.MIN_VALUE)), + p(1, value(Float.NaN)), + p(1, value(Float.NEGATIVE_INFINITY)), + p(1, value(Float.POSITIVE_INFINITY)), + p(1, value(Float.MAX_VALUE - 1F)), + p(91, arbFloat.gen))); + } + })); + + /** + * An arbitrary implementation for string values. + */ + public static final Arbitrary arbString = + arbitrary(arbList(arbCharacter).gen.map(new F, String>() { + public String f(final List cs) { + return asString(cs); + } + })); + + /** + * An arbitrary implementation for string values with characters in the US-ASCII range. + */ + public static final Arbitrary arbUSASCIIString = + arbitrary(arbList(arbCharacter).gen.map(new F, String>() { + public String f(final List cs) { + return asString(cs.map(new F() { + public Character f(final Character c) { + return (char) (c % 128); + } + })); + } + })); + + /** + * An arbitrary implementation for string values with alpha-numeric characters. + */ + public static final Arbitrary arbAlphaNumString = + arbitrary(arbList(arbitrary(elements(range(charEnumerator, 'a', 'z').append( + range(charEnumerator, 'A', 'Z')).append( + range(charEnumerator, '0', '9')).toArray().array(Character[].class)))).gen.map(asString())); + + /** + * An arbitrary implementation for string buffer values. + */ + public static final Arbitrary arbStringBuffer = + arbitrary(arbString.gen.map(new F() { + public StringBuffer f(final String s) { + return new StringBuffer(s); + } + })); + + /** + * An arbitrary implementation for string builder values. + */ + public static final Arbitrary arbStringBuilder = + arbitrary(arbString.gen.map(new F() { + public StringBuilder f(final String s) { + return new StringBuilder(s); + } + })); + + /** + * Returns an arbitrary implementation for generators. + * + * @param aa an arbitrary implementation for the type over which the generator is defined. + * @return An arbitrary implementation for generators. + */ + public static Arbitrary> arbGen(final Arbitrary aa) { + return arbitrary(sized(new F>>() { + @SuppressWarnings({"IfMayBeConditional"}) + public Gen> f(final Integer i) { + if (i == 0) + return fail(); + else + return aa.gen.map(new F>() { + public Gen f(final A a) { + return value(a); + } + }).resize(i - 1); + } + })); + } + + /** + * Returns an arbitrary implementation for optional values. + * + * @param aa an arbitrary implementation for the type over which the optional value is defined. + * @return An arbitrary implementation for optional values. + */ + public static Arbitrary> arbOption(final Arbitrary aa) { + return arbitrary(sized(new F>>() { + public Gen> f(final Integer i) { + return i == 0 ? + value(Option.none()) : + aa.gen.map(new F>() { + public Option f(final A a) { + return some(a); + } + }).resize(i - 1); + } + })); + } + + /** + * Returns an arbitrary implementation for the disjoint union. + * + * @param aa An arbitrary implementation for the type over which one side of the disjoint union is + * defined. + * @param ab An arbitrary implementation for the type over which one side of the disjoint union is + * defined. + * @return An arbitrary implementation for the disjoint union. + */ + @SuppressWarnings({"unchecked"}) + public static Arbitrary> arbEither(final Arbitrary aa, final Arbitrary ab) { + final Gen> left = aa.gen.map(new F>() { + public Either f(final A a) { + return left(a); + } + }); + final Gen> right = ab.gen.map(new F>() { + public Either f(final B b) { + return right(b); + } + }); + return arbitrary(oneOf(list(left, right))); + } + + /** + * Returns an arbitrary implementation for lists. + * + * @param aa An arbitrary implementation for the type over which the list is defined. + * @return An arbitrary implementation for lists. + */ + public static Arbitrary> arbList(final Arbitrary aa) { + return arbitrary(listOf(aa.gen)); + } + + /** + * Returns an arbitrary implementation for streams. + * + * @param aa An arbitrary implementation for the type over which the stream is defined. + * @return An arbitrary implementation for streams. + */ + public static Arbitrary> arbStream(final Arbitrary aa) { + return arbitrary(arbList(aa).gen.map(new F, Stream>() { + public Stream f(final List as) { + return as.toStream(); + } + })); + } + + /** + * Returns an arbitrary implementation for arrays. + * + * @param aa An arbitrary implementation for the type over which the array is defined. + * @return An arbitrary implementation for arrays. + */ + public static Arbitrary> arbArray(final Arbitrary aa) { + return arbitrary(arbList(aa).gen.map(new F, Array>() { + public Array f(final List as) { + return as.toArray(); + } + })); + } + + /** + * Returns an arbitrary implementation for throwables. + * + * @param as An arbitrary used for the throwable message. + * @return An arbitrary implementation for throwables. + */ + public static Arbitrary arbThrowable(final Arbitrary as) { + return arbitrary(as.gen.map(new F() { + public Throwable f(final String msg) { + return new Throwable(msg); + } + })); + } + + /** + * An arbitrary implementation for throwables. + */ + public static final Arbitrary arbThrowable = arbThrowable(arbString); + + // BEGIN java.util + + /** + * Returns an arbitrary implementation for array lists. + * + * @param aa An arbitrary implementation for the type over which the array list is defined. + * @return An arbitrary implementation for array lists. + */ + public static Arbitrary> arbArrayList(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, ArrayList>() { + public ArrayList f(final Array a) { + return new ArrayList(a.toCollection()); + } + })); + } + + /** + * An arbitrary implementation for bit sets. + */ + public static final Arbitrary arbBitSet = + arbitrary(arbList(arbBoolean).gen.map(new F, BitSet>() { + public BitSet f(final List bs) { + final BitSet s = new BitSet(bs.length()); + bs.zipIndex().foreachDoEffect(new Effect1>() { + public void f(final P2 bi) { + s.set(bi._2(), bi._1()); + } + }); + return s; + } + })); + + /** + * An arbitrary implementation for calendars. + */ + public static final Arbitrary arbCalendar = arbitrary(arbLong.gen.map(new F() { + public Calendar f(final Long i) { + final Calendar c = Calendar.getInstance(); + c.setTimeInMillis(i); + return c; + } + })); + + /** + * An arbitrary implementation for dates. + */ + public static final Arbitrary arbDate = arbitrary(arbLong.gen.map(new F() { + public Date f(final Long i) { + return new Date(i); + } + })); + + /** + * Returns an arbitrary implementation for a Java enumeration. + * + * @param clazz The type of enum to return an arbtrary of. + * @return An arbitrary for instances of the supplied enum type. + */ + public static > Arbitrary arbEnumValue(final Class clazz) { + return arbitrary(Gen.elements(clazz.getEnumConstants())); + } + + /** + * Returns an arbitrary implementation for enum maps. + * + * @param ak An arbitrary implementation for the type over which the enum map's keys are defined. + * @param av An arbitrary implementation for the type over which the enum map's values are + * defined. + * @return An arbitrary implementation for enum maps. + */ + public static , V> Arbitrary> arbEnumMap(final Arbitrary ak, + final Arbitrary av) { + return arbitrary(arbHashtable(ak, av).gen.map(new F, EnumMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public EnumMap f(final Hashtable ht) { + return new EnumMap(ht); + } + })); + } + + /** + * Returns an arbitrary implementation for enum sets. + * + * @param aa An arbitrary implementation for the type over which the enum set is defined. + * @return An arbitrary implementation for enum sets. + */ + public static > Arbitrary> arbEnumSet(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, EnumSet>() { + public EnumSet f(final Array a) { + return copyOf(a.toCollection()); + } + })); + } + + /** + * An arbitrary implementation for gregorian calendars. + */ + public static final Arbitrary arbGregorianCalendar = + arbitrary(arbLong.gen.map(new F() { + public GregorianCalendar f(final Long i) { + final GregorianCalendar c = new GregorianCalendar(); + c.setTimeInMillis(i); + return c; + } + })); + + /** + * Returns an arbitrary implementation for hash maps. + * + * @param ak An arbitrary implementation for the type over which the hash map's keys are defined. + * @param av An arbitrary implementation for the type over which the hash map's values are + * defined. + * @return An arbitrary implementation for hash maps. + */ + public static Arbitrary> arbHashMap(final Arbitrary ak, final Arbitrary av) { + return arbitrary(arbHashtable(ak, av).gen.map(new F, HashMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public HashMap f(final Hashtable ht) { + return new HashMap(ht); + } + })); + } + + /** + * Returns an arbitrary implementation for hash sets. + * + * @param aa An arbitrary implementation for the type over which the hash set is defined. + * @return An arbitrary implementation for hash sets. + */ + public static Arbitrary> arbHashSet(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, HashSet>() { + public HashSet f(final Array a) { + return new HashSet(a.toCollection()); + } + })); + } + + /** + * Returns an arbitrary implementation for hash tables. + * + * @param ak An arbitrary implementation for the type over which the hash table's keys are + * defined. + * @param av An arbitrary implementation for the type over which the hash table's values are + * defined. + * @return An arbitrary implementation for hash tables. + */ + public static Arbitrary> arbHashtable(final Arbitrary ak, final Arbitrary av) { + return arbitrary(arbList(ak).gen.bind(arbList(av).gen, new F, F, Hashtable>>() { + public F, Hashtable> f(final List ks) { + return new F, Hashtable>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Hashtable f(final List vs) { + final Hashtable t = new Hashtable(); + + ks.zip(vs).foreachDoEffect(new Effect1>() { + public void f(final P2 kv) { + t.put(kv._1(), kv._2()); + } + }); + + return t; + } + }; + } + })); + } + + /** + * Returns an arbitrary implementation for identity hash maps. + * + * @param ak An arbitrary implementation for the type over which the identity hash map's keys are + * defined. + * @param av An arbitrary implementation for the type over which the identity hash map's values + * are defined. + * @return An arbitrary implementation for identity hash maps. + */ + public static Arbitrary> arbIdentityHashMap(final Arbitrary ak, + final Arbitrary av) { + return arbitrary(arbHashtable(ak, av).gen.map(new F, IdentityHashMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public IdentityHashMap f(final Hashtable ht) { + return new IdentityHashMap(ht); + } + })); + } + + /** + * Returns an arbitrary implementation for linked hash maps. + * + * @param ak An arbitrary implementation for the type over which the linked hash map's keys are + * defined. + * @param av An arbitrary implementation for the type over which the linked hash map's values are + * defined. + * @return An arbitrary implementation for linked hash maps. + */ + public static Arbitrary> arbLinkedHashMap(final Arbitrary ak, final Arbitrary av) { + return arbitrary(arbHashtable(ak, av).gen.map(new F, LinkedHashMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public LinkedHashMap f(final Hashtable ht) { + return new LinkedHashMap(ht); + } + })); + } + + /** + * Returns an arbitrary implementation for hash sets. + * + * @param aa An arbitrary implementation for the type over which the hash set is defined. + * @return An arbitrary implementation for hash sets. + */ + public static Arbitrary> arbLinkedHashSet(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, LinkedHashSet>() { + public LinkedHashSet f(final Array a) { + return new LinkedHashSet(a.toCollection()); + } + })); + } + + /** + * Returns an arbitrary implementation for linked lists. + * + * @param aa An arbitrary implementation for the type over which the linked list is defined. + * @return An arbitrary implementation for linked lists. + */ + public static Arbitrary> arbLinkedList(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, LinkedList>() { + public LinkedList f(final Array a) { + return new LinkedList(a.toCollection()); + } + })); + } + + /** + * Returns an arbitrary implementation for priority queues. + * + * @param aa An arbitrary implementation for the type over which the priority queue is defined. + * @return An arbitrary implementation for priority queues. + */ + public static Arbitrary> arbPriorityQueue(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, PriorityQueue>() { + public PriorityQueue f(final Array a) { + return new PriorityQueue(a.toCollection()); + } + })); + } + + /** + * An arbitrary implementation for properties. + */ + public static final Arbitrary arbProperties = + arbitrary(arbHashtable(arbString, arbString).gen.map(new F, Properties>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Properties f(final Hashtable ht) { + final Properties p = new Properties(); + + for (final String k : ht.keySet()) { + p.setProperty(k, ht.get(k)); + } + + return p; + } + })); + + /** + * Returns an arbitrary implementation for stacks. + * + * @param aa An arbitrary implementation for the type over which the stack is defined. + * @return An arbitrary implementation for stacks. + */ + public static Arbitrary> arbStack(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, Stack>() { + public Stack f(final Array a) { + final Stack s = new Stack(); + s.addAll(a.toCollection()); + return s; + } + })); + } + + /** + * Returns an arbitrary implementation for tree maps. + * + * @param ak An arbitrary implementation for the type over which the tree map's keys are defined. + * @param av An arbitrary implementation for the type over which the tree map's values are + * defined. + * @return An arbitrary implementation for tree maps. + */ + public static Arbitrary> arbTreeMap(final Arbitrary ak, final Arbitrary av) { + return arbitrary(arbHashtable(ak, av).gen.map(new F, TreeMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public TreeMap f(final Hashtable ht) { + return new TreeMap(ht); + } + })); + } + + /** + * Returns an arbitrary implementation for tree sets. + * + * @param aa An arbitrary implementation for the type over which the tree set is defined. + * @return An arbitrary implementation for tree sets. + */ + public static Arbitrary> arbTreeSet(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, TreeSet>() { + public TreeSet f(final Array a) { + return new TreeSet(a.toCollection()); + } + })); + } + + /** + * Returns an arbitrary implementation for vectors. + * + * @param aa An arbitrary implementation for the type over which the vector is defined. + * @return An arbitrary implementation for vectors. + */ + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public static Arbitrary> arbVector(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, Vector>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Vector f(final Array a) { + return new Vector(a.toCollection()); + } + })); + } + + /** + * Returns an arbitrary implementation for weak hash maps. + * + * @param ak An arbitrary implementation for the type over which the weak hash map's keys are + * defined. + * @param av An arbitrary implementation for the type over which the weak hash map's values are + * defined. + * @return An arbitrary implementation for weak hash maps. + */ + public static Arbitrary> arbWeakHashMap(final Arbitrary ak, final Arbitrary av) { + return arbitrary(arbHashtable(ak, av).gen.map(new F, WeakHashMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public WeakHashMap f(final Hashtable ht) { + return new WeakHashMap(ht); + } + })); + } + + // END java.util + + // BEGIN java.util.concurrent + + /** + * Returns an arbitrary implementation for array blocking queues. + * + * @param aa An arbitrary implementation for the type over which the array blocking queue is + * defined. + * @return An arbitrary implementation for array blocking queues. + */ + public static Arbitrary> arbArrayBlockingQueue(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.bind(arbInteger.gen, arbBoolean.gen, + new F, F>>>() { + public F>> f(final Array a) { + return new F>>() { + public F> f(final Integer capacity) { + return new F>() { + public ArrayBlockingQueue f(final Boolean fair) { + return new ArrayBlockingQueue(a.length() + abs(capacity), + fair, a.toCollection()); + } + }; + } + }; + } + })); + } + + /** + * Returns an arbitrary implementation for concurrent hash maps. + * + * @param ak An arbitrary implementation for the type over which the concurrent hash map's keys + * are defined. + * @param av An arbitrary implementation for the type over which the concurrent hash map's values + * are defined. + * @return An arbitrary implementation for concurrent hash maps. + */ + public static Arbitrary> arbConcurrentHashMap(final Arbitrary ak, + final Arbitrary av) { + return arbitrary(arbHashtable(ak, av).gen.map(new F, ConcurrentHashMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public ConcurrentHashMap f(final Hashtable ht) { + return new ConcurrentHashMap(ht); + } + })); + } + + /** + * Returns an arbitrary implementation for concurrent linked queues. + * + * @param aa An arbitrary implementation for the type over which the concurrent linked queue is + * defined. + * @return An arbitrary implementation for concurrent linked queues. + */ + public static Arbitrary> arbConcurrentLinkedQueue(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, ConcurrentLinkedQueue>() { + public ConcurrentLinkedQueue f(final Array a) { + return new ConcurrentLinkedQueue(a.toCollection()); + } + })); + } + + /** + * Returns an arbitrary implementation for copy-on-write array lists. + * + * @param aa An arbitrary implementation for the type over which the copy-on-write array list is + * defined. + * @return An arbitrary implementation for copy-on-write array lists. + */ + public static Arbitrary> arbCopyOnWriteArrayList(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, CopyOnWriteArrayList>() { + public CopyOnWriteArrayList f(final Array a) { + return new CopyOnWriteArrayList(a.toCollection()); + } + })); + } + + /** + * Returns an arbitrary implementation for copy-on-write array sets. + * + * @param aa An arbitrary implementation for the type over which the copy-on-write array set is + * defined. + * @return An arbitrary implementation for copy-on-write array sets. + */ + public static Arbitrary> arbCopyOnWriteArraySet(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, CopyOnWriteArraySet>() { + public CopyOnWriteArraySet f(final Array a) { + return new CopyOnWriteArraySet(a.toCollection()); + } + })); + } + + /** + * Returns an arbitrary implementation for delay queues. + * + * @param aa An arbitrary implementation for the type over which the delay queue is defined. + * @return An arbitrary implementation for delay queues. + */ + public static Arbitrary> arbDelayQueue(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, DelayQueue>() { + public DelayQueue f(final Array a) { + return new DelayQueue(a.toCollection()); + } + })); + } + + /** + * Returns an arbitrary implementation for linked blocking queues. + * + * @param aa An arbitrary implementation for the type over which the linked blocking queue is + * defined. + * @return An arbitrary implementation for linked blocking queues. + */ + public static Arbitrary> arbLinkedBlockingQueue(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, LinkedBlockingQueue>() { + public LinkedBlockingQueue f(final Array a) { + return new LinkedBlockingQueue(a.toCollection()); + } + })); + } + + /** + * Returns an arbitrary implementation for priority blocking queues. + * + * @param aa An arbitrary implementation for the type over which the priority blocking queue is + * defined. + * @return An arbitrary implementation for priority blocking queues. + */ + public static Arbitrary> arbPriorityBlockingQueue(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.map(new F, PriorityBlockingQueue>() { + public PriorityBlockingQueue f(final Array a) { + return new PriorityBlockingQueue(a.toCollection()); + } + })); + } + + /** + * Returns an arbitrary implementation for priority blocking queues. + * + * @param aa An arbitrary implementation for the type over which the priority blocking queue is + * defined. + * @return An arbitrary implementation for priority blocking queues. + */ + public static Arbitrary> arbSynchronousQueue(final Arbitrary aa) { + return arbitrary(arbArray(aa).gen.bind(arbBoolean.gen, new F, F>>() { + public F> f(final Array a) { + return new F>() { + public SynchronousQueue f(final Boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + q.addAll(a.toCollection()); + return q; + } + }; + } + })); + } + + // END java.util.concurrent + + // BEGIN java.sql + + /** + * An arbitrary implementation for SQL dates. + */ + public static final Arbitrary arbSQLDate = arbitrary(arbLong.gen.map(new F() { + public java.sql.Date f(final Long i) { + return new java.sql.Date(i); + } + })); + + /** + * An arbitrary implementation for SQL times. + */ + public static final Arbitrary Arbitrary> arbP1(final Arbitrary aa) { + return arbitrary(aa.gen.map(new F>() { + public P1 f(final A a) { + return p(a); + } + })); + } + + /** + * Returns an arbitrary implementation for product-2 values. + * + * @param aa An arbitrary implementation for one of the types over which the product-2 is + * defined. + * @param ab An Arbitrary implementation for one of the types over which the product-2 is + * defined. + * @return An arbitrary implementation for product-2 values. + */ + public static Arbitrary> arbP2(final Arbitrary aa, final Arbitrary ab) { + return arbitrary(aa.gen.bind(ab.gen, new F>>() { + public F> f(final A a) { + return new F>() { + public P2 f(final B b) { + return p(a, b); + } + }; + } + })); + } + + /** + * Returns an arbitrary implementation for product-3 values. + * + * @param aa An arbitrary implementation for one of the types over which the product-3 is + * defined. + * @param ab An Arbitrary implementation for one of the types over which the product-3 is + * defined. + * @param ac An arbitrary implementation for one of the types over which the product-3 is + * defined. + * @return An arbitrary implementation for product-3 values. + */ + public static Arbitrary> arbP3(final Arbitrary aa, final Arbitrary ab, + final Arbitrary ac) { + return arbitrary(aa.gen.bind(ab.gen, ac.gen, new F>>>() { + public F>> f(final A a) { + return new F>>() { + public F> f(final B b) { + return new F>() { + public P3 f(final C c) { + return p(a, b, c); + } + }; + } + }; + } + })); + } + + /** + * Returns an arbitrary implementation for product-4 values. + * + * @param aa An arbitrary implementation for one of the types over which the product-4 is + * defined. + * @param ab An Arbitrary implementation for one of the types over which the product-4 is + * defined. + * @param ac An arbitrary implementation for one of the types over which the product-4 is + * defined. + * @param ad An arbitrary implementation for one of the types over which the product-4 is + * defined. + * @return An arbitrary implementation for product-4 values. + */ + public static Arbitrary> arbP4(final Arbitrary aa, final Arbitrary ab, + final Arbitrary ac, final Arbitrary ad) { + return arbitrary(aa.gen.bind(ab.gen, ac.gen, ad.gen, new F>>>>() { + public F>>> f(final A a) { + return new F>>>() { + public F>> f(final B b) { + return new F>>() { + public F> f(final C c) { + return new F>() { + public P4 f(final D d) { + return p(a, b, c, d); + } + }; + } + }; + } + }; + } + })); + } + + /** + * Returns an arbitrary implementation for product-5 values. + * + * @param aa An arbitrary implementation for one of the types over which the product-5 is + * defined. + * @param ab An Arbitrary implementation for one of the types over which the product-5 is + * defined. + * @param ac An arbitrary implementation for one of the types over which the product-5 is + * defined. + * @param ad An arbitrary implementation for one of the types over which the product-5 is + * defined. + * @param ae An arbitrary implementation for one of the types over which the product-5 is + * defined. + * @return An arbitrary implementation for product-5 values. + */ + public static Arbitrary> arbP5(final Arbitrary aa, final Arbitrary ab, + final Arbitrary ac, final Arbitrary ad, + final Arbitrary ae) { + return arbitrary(aa.gen.bind(ab.gen, ac.gen, ad.gen, ae.gen, new F>>>>>() { + public F>>>> f(final A a) { + return new F>>>>() { + public F>>> f(final B b) { + return new F>>>() { + public F>> f(final C c) { + return new F>>() { + public F> f(final D d) { + return new F>() { + public P5 f(final E e) { + return p(a, b, c, d, e); + } + }; + } + }; + } + }; + } + }; + } + })); + } + + /** + * Returns an arbitrary implementation for product-6 values. + * + * @param aa An arbitrary implementation for one of the types over which the product-6 is + * defined. + * @param ab An Arbitrary implementation for one of the types over which the product-6 is + * defined. + * @param ac An arbitrary implementation for one of the types over which the product-6 is + * defined. + * @param ad An arbitrary implementation for one of the types over which the product-6 is + * defined. + * @param ae An arbitrary implementation for one of the types over which the product-6 is + * defined. + * @param af An arbitrary implementation for one of the types over which the product-7 is + * defined. + * @return An arbitrary implementation for product-6 values. + */ + public static Arbitrary> arbP6(final Arbitrary aa, final Arbitrary ab, + final Arbitrary ac, final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af) { + return arbitrary(aa.gen.bind(ab.gen, ac.gen, ad.gen, ae.gen, af.gen, + new F>>>>>>() { + public F>>>>> f(final A a) { + return new F>>>>>() { + public F>>>> f(final B b) { + return new F>>>>() { + public F>>> f(final C c) { + return new F>>>() { + public F>> f(final D d) { + return new F>>() { + public F> f(final E e) { + return new F>() { + public P6 f(final F$ f) { + return p(a, b, c, d, e, f); + } + }; + } + }; + } + }; + } + }; + } + }; + } + })); + } + + /** + * Returns an arbitrary implementation for product-7 values. + * + * @param aa An arbitrary implementation for one of the types over which the product-7 is + * defined. + * @param ab An Arbitrary implementation for one of the types over which the product-7 is + * defined. + * @param ac An arbitrary implementation for one of the types over which the product-7 is + * defined. + * @param ad An arbitrary implementation for one of the types over which the product-7 is + * defined. + * @param ae An arbitrary implementation for one of the types over which the product-7 is + * defined. + * @param af An arbitrary implementation for one of the types over which the product-7 is + * defined. + * @param ag An arbitrary implementation for one of the types over which the product-8 is + * defined. + * @return An arbitrary implementation for product-7 values. + */ + public static Arbitrary> arbP7(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Arbitrary ag) { + return arbitrary(aa.gen.bind(ab.gen, ac.gen, ad.gen, ae.gen, af.gen, ag.gen, + new F>>>>>>>() { + public F>>>>>> f(final A a) { + return new F>>>>>>() { + public F>>>>> f(final B b) { + return new F>>>>>() { + public F>>>> f(final C c) { + return new F>>>>() { + public F>>> f(final D d) { + return new F>>>() { + public F>> f(final E e) { + return new F>>() { + public F> f(final F$ f) { + return new F>() { + public P7 f(final G g) { + return p(a, b, c, d, e, f, g); + } + }; + } + }; + } + }; + } + }; + } + }; + } + }; + } + })); + } + + /** + * Returns an arbitrary implementation for product-8 values. + * + * @param aa An arbitrary implementation for one of the types over which the product-8 is + * defined. + * @param ab An Arbitrary implementation for one of the types over which the product-8 is + * defined. + * @param ac An arbitrary implementation for one of the types over which the product-8 is + * defined. + * @param ad An arbitrary implementation for one of the types over which the product-8 is + * defined. + * @param ae An arbitrary implementation for one of the types over which the product-8 is + * defined. + * @param af An arbitrary implementation for one of the types over which the product-8 is + * defined. + * @param ag An arbitrary implementation for one of the types over which the product-8 is + * defined. + * @param ah An arbitrary implementation for one of the types over which the product-8 is + * defined. + * @return An arbitrary implementation for product-8 values. + */ + public static Arbitrary> arbP8(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Arbitrary ag, + final Arbitrary ah) { + return arbitrary(aa.gen.bind(ab.gen, ac.gen, ad.gen, ae.gen, af.gen, ag.gen, ah.gen, + new F>>>>>>>>() { + public F>>>>>>> f( + final A a) { + return new F>>>>>>>() { + public F>>>>>> f( + final B b) { + return new F>>>>>>() { + public F>>>>> f( + final C c) { + return new F>>>>>() { + public F>>>> f( + final D d) { + return new F>>>>() { + public F>>> f(final E e) { + return new F>>>() { + public F>> f(final F$ f) { + return new F>>() { + public F> f(final G g) { + return new F>() { + public P8 f(final H h) { + return p(a, b, c, d, e, f, g, h); + } + }; + } + }; + } + }; + } + }; + } + }; + } + }; + } + }; + } + })); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/Arg.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/Arg.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,61 @@ +package fj.test; + +import fj.F; +import fj.Show; + +import static fj.Show.anyShow; +import static fj.Show.showS; + +/** + * An argument used in a property that may have undergone shrinking following falsification. + * + * @version %build.number% + */ +public final class Arg { + private final T value; + private final int shrinks; + + private Arg(final T value, final int shrinks) { + this.value = value; + this.shrinks = shrinks; + } + + /** + * Construct a property argument with the given value and number of shrinks. + * + * @param value The value to construct an argument with. + * @param shrinks The number of shrinks to construct an argument with. + * @return A new argument. + */ + public static Arg arg(final T value, final int shrinks) { + return new Arg(value, shrinks); + } + + /** + * Returns the argument's value. + * + * @return The argument's value. + */ + public Object value() { + return value; + } + + /** + * Returns the argument's number of shrinks following falsification. + * + * @return The argument's number of shrinks following falsification. + */ + public int shrinks() { + return shrinks; + } + + /** + * The rendering of an argument (uses {@link Object#toString()} for the argument value). + */ + public static final Show> argShow = showS(new F, String>() { + public String f(final Arg arg) { + return anyShow().showS(arg.value) + + (arg.shrinks > 0 ? " (" + arg.shrinks + " shrink" + (arg.shrinks == 1 ? "" : 's') + ')' : ""); + } + }); +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/Bool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/Bool.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,98 @@ +package fj.test; + +import fj.P1; +import static fj.test.Property.prop; + +/** + * A boolean wrapper that works well with properties. + * + * @version %build.number% + */ +public final class Bool { + private final boolean b; + + private static final Bool t = new Bool(true); + private static final Bool f = new Bool(false); + + private Bool(final boolean b) { + this.b = b; + } + + /** + * Returns true if this value is true, false otherwise. + * + * @return true if this value is true, false otherwise. + */ + public boolean is() { + return b; + } + + /** + * Returns false if this value is true, true otherwise. + * + * @return false if this value is true, true otherwise. + */ + public boolean isNot() { + return !b; + } + + /** + * Returns a property that produces a result only if this value is true. The result will be taken + * from the given property. + * + * @param p The property to return if this value is true. + * @return a property that produces a result only if this value is true. + */ + public Property implies(final P1 p) { + return Property.implies(b, p); + } + + /** + * Returns a property that produces a result only if this value is true. The result will be taken + * from the given property. + * + * @param p The property to return if this value is true. + * @return a property that produces a result only if this value is true. + */ + public Property implies(final Property p) { + return Property.implies(b, new P1() { + public Property _1() { + return p; + } + }); + } + + /** + * Returns a property that produces a result only if this value is true. + * + * @param c The value to construct a property with to return if this value is true. + * @return a property that produces a result only if this value is true. + */ + public Property implies(final Bool c) { + return implies(prop(c.b)); + } + + /** + * Returns a property that produces a result only if this value is true. + * + * @param c The value to construct a property with to return if this value is true. + * @return a property that produces a result only if this value is true. + */ + public Property implies(final boolean c) { + return Property.implies(b, new P1() { + public Property _1() { + return prop(c); + } + }); + } + + /** + * Construct a Bool from the given value. + * + * @param b The value to construct a Bool with. + * @return A Bool from the given value. + */ + public static Bool bool(final boolean b) { + return b ? t : f; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/CheckResult.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/CheckResult.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,299 @@ +package fj.test; + +import static fj.Bottom.decons; +import fj.F; +import fj.Show; +import fj.data.List; +import fj.data.Option; +import static fj.data.Option.some; +import static fj.Show.listShow; +import static fj.Show.showS; +import static fj.test.Arg.argShow; + +import java.io.StringWriter; +import java.io.PrintWriter; + +/** + * An enumeration of the possible results after checking a property. A CheckResult may + * be in one of six states: + *

    + *
  1. Passed
  2. + *
  3. Proven
  4. + *
  5. Falsified
  6. + *
  7. Exhausted
  8. + *
  9. Exception executing the property
  10. + *
  11. Exception generating values to check the property
  12. + *
+ * + * @version %build.number% + */ +public final class CheckResult { + private final R r; + private final Option>> args; + private final Option ex; + private final int succeeded; + private final int discarded; + + private enum R { + Passed, Proven, Falsified, Exhausted, PropException, GenException + } + + private CheckResult(final R r, final Option>> args, final Option ex, final int succeeded, + final int discarded) { + this.r = r; + this.args = args; + this.ex = ex; + this.succeeded = succeeded; + this.discarded = discarded; + } + + /** + * Returns a result that the property has passed. + * + * @param succeeded The number of checks that succeeded. + * @param discarded The number of checks that were discarded. + * @return A result that the property has passed. + */ + public static CheckResult passed(final int succeeded, final int discarded) { + return new CheckResult(R.Passed, Option.>>none(), Option.none(), succeeded, discarded); + } + + /** + * Returns a result that the property has been proven. + * + * @param args The arguments used to prove the property. + * @param succeeded The number of checks that succeeded. + * @param discarded The number of checks that were discarded. + * @return A result that the property has been proven. + */ + public static CheckResult proven(final List> args, final int succeeded, final int discarded) { + return new CheckResult(R.Proven, some(args), Option.none(), succeeded, discarded); + } + + /** + * Returns a result that the property has been falsified. + * + * @param args The arguments used to falsify the property. + * @param succeeded The number of checks that succeeded. + * @param discarded The number of checks that were discarded. + * @return A result that the property has been falsified. + */ + public static CheckResult falsified(final List> args, final int succeeded, final int discarded) { + return new CheckResult(R.Falsified, some(args), Option.none(), succeeded, discarded); + } + + /** + * Returns a result that the property been exhausted in checking. + * + * @param succeeded The number of checks that succeeded. + * @param discarded The number of checks that were discarded. + * @return A result that the property has been exhausted in checking. + */ + public static CheckResult exhausted(final int succeeded, final int discarded) { + return new CheckResult(R.Exhausted, Option.>>none(), Option.none(), succeeded, discarded); + } + + /** + * Returns a result that checking the property threw an exception. + * + * @param args The arguments used when the exception was thrown. + * @param ex The exception that was thrown. + * @param succeeded The number of checks that succeeded. + * @param discarded The number of checks that were discarded. + * @return A result that checking the property threw an exception. + */ + public static CheckResult propException(final List> args, final Throwable ex, final int succeeded, + final int discarded) { + return new CheckResult(R.PropException, some(args), some(ex), succeeded, discarded); + } + + + /** + * Returns a result that generating values to check the property threw an exception. + * + * @param ex The exception that was thrown. + * @param succeeded The number of checks that succeeded. + * @param discarded The number of checks that were discarded. + * @return A result that generating values to check the property threw an exception. + */ + public static CheckResult genException(final Throwable ex, final int succeeded, final int discarded) { + return new CheckResult(R.GenException, Option.>>none(), some(ex), succeeded, discarded); + } + + /** + * Returns true if this result is passed, false otherwise. + * + * @return true if this result is passed, false otherwise. + */ + public boolean isPassed() { + return r == R.Passed; + } + + /** + * Returns true if this result is proven, false otherwise. + * + * @return true if this result is proven, false otherwise. + */ + public boolean isProven() { + return r == R.Proven; + } + + /** + * Returns true if this result is falsified, false otherwise. + * + * @return true if this result is falsified, false otherwise. + */ + public boolean isFalsified() { + return r == R.Falsified; + } + + /** + * Returns true if this result is exhausted, false otherwise. + * + * @return true if this result is exhausted, false otherwise. + */ + public boolean isExhausted() { + return r == R.Exhausted; + } + + + /** + * Returns true if this result is an exception during property execution, + * false otherwise. + * + * @return true if this result is an exception during property execution, + * false otherwise. + */ + public boolean isPropException() { + return r == R.PropException; + } + + /** + * Returns true if this result is an exception during generating of values for + * property checking, false otherwise. + * + * @return true if this result is an exception during generating of values for + * property checking, false otherwise. + */ + public boolean isGenException() { + return r == R.GenException; + } + + /** + * Returns the arguments if the result is one of; proven, falsified or exception during property + * execution, otherwise, no arguments are returned. + * + * @return The arguments if the result is one of; proven, falsified or exception during property + * execution, otherwise, no arguments are returned. + */ + public Option>> args() { + return args; + } + + /** + * Returns the execption if the result is one of; exception during property execution or exception + * during argument value generation, otherwise, no exception are returned. + * + * @return The execption if the result is one of; exception during property execution or exception + * during argument value generation, otherwise, no exception are returned. + */ + public Option exception() { + return ex; + } + + /** + * Returns the number of succeeded checks of the property in this result. + * + * @return The number of succeeded checks of the property in this result. + */ + public int succeeded() { + return succeeded; + } + + /** + * Returns the number of discarded checks of the property in this result. + * + * @return The number of discarded checks of the property in this result. + */ + public int discarded() { + return discarded; + } + + /** + * A rendering of a check result that summarises in one line. + * + * @param sa The rendering of arguments. + * @return A rendering of a check result that summarises in one line. + */ + public static Show summary(final Show> sa) { + return showS(new F() { + private String test(final CheckResult r) { + return r.succeeded() == 1 ? "test" : "tests"; + } + + private String arguments(final CheckResult r) { + final List> args = r.args().some(); + return args.length() == 1 ? "argument: " + sa.showS(args.head()) : "arguments: " + listShow(sa).showS(args); + } + + @SuppressWarnings({"ThrowableResultOfMethodCallIgnored"}) + public String f(final CheckResult r) { + if (r.isProven()) + return "OK, property proven with " + arguments(r); + else if (r.isPassed()) + return "OK, passed " + r.succeeded() + ' ' + test(r) + + (r.discarded() > 0 ? " (" + r.discarded() + " discarded)" : "") + '.'; + else if (r.isFalsified()) + return "Falsified after " + r.succeeded() + " passed " + test(r) + " with " + arguments(r); + else if (r.isExhausted()) + return "Gave up after " + r.succeeded() + " passed " + test(r) + " and " + r.discarded() + + " discarded tests."; + else if (r.isPropException()) { + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); + r.exception().some().printStackTrace(pw); + return "Exception on property evaluation with " + arguments(r) + System.getProperty("line.separator") + sw; + } else if (r.isGenException()) { + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); + r.exception().some().printStackTrace(pw); + return "Exception on argument generation " + System.getProperty("line.separator") + sw; + } else + throw decons(r.getClass()); + } + }); + } + + /** + * A rendering of a check result that summarises in one line. + */ + public static final Show summary = summary(argShow); + + /** + * A rendering of a check result that summarises in one line but throws an exception in the result + * is a failure (falsified, property exception or generator exception). + */ + public static final Show summaryEx = summaryEx(argShow); + + /** + * A rendering of a check result that summarises in one line but throws an exception in the result + * is a failure (falsified, property exception or generator exception). + * + * @param sa The rendering of arguments. + * @return A rendering of a check result that summarises in one line but throws an exception in + * the result is a failure (falsified, property exception or generator exception). + */ + public static Show summaryEx(final Show> sa) { + return showS(new F() { + public String f(final CheckResult r) { + final String s = summary(sa).show(r).toString(); + if (r.isProven() || r.isPassed() || r.isExhausted()) + return s; + else if (r.isFalsified() || r.isPropException() || r.isGenException()) + throw new Error(s); + else + throw decons(r.getClass()); + } + }); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/Coarbitrary.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/Coarbitrary.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,1190 @@ +package fj.test; + +import fj.*; + +import static fj.Function.curry; +import static fj.P.p; + +import fj.data.*; + +import static fj.data.Array.array; +import static fj.data.List.fromString; +import static fj.data.List.nil; + +import static fj.test.Variant.variant; + +import static java.lang.Double.doubleToRawLongBits; +import static java.lang.Float.floatToRawIntBits; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Calendar; +import java.util.Date; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.PriorityQueue; +import java.util.Properties; +import java.util.Stack; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.Vector; +import java.util.WeakHashMap; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Delayed; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.SynchronousQueue; + +/** + * Transforms a type and a generator to produce a new generator. This function is used to generate + * {@link Arbitrary arbitrary} functions. + * + * @version %build.number% + */ +public abstract class Coarbitrary { + /** + * Transforms the given value and generator to a new generator with a high probability of being + * independent. + * + * @param a The value to produce the generator from. + * @param g The generator to produce the new generator from. + * @return A new generator with a high probability of being independent. + */ + public abstract Gen coarbitrary(A a, Gen g); + + + /** + * A curried version of {@link #coarbitrary(Object, Gen)}. + * + * @param a The value to produce the generator from. + * @return A curried version of {@link #coarbitrary(Object, Gen)}. + */ + public final F, Gen> coarbitrary(final A a) { + return new F, Gen>() { + public Gen f(final Gen g) { + return coarbitrary(a, g); + } + }; + } + + /** + * Composes the given function with this coarbitrary to produce a new coarbitrary. + * + * @param f The function to compose. + * @return A new coarbitrary composed with the given function. + */ + public final Coarbitrary compose(final F f) { + return new Coarbitrary() { + public Gen coarbitrary(final B b, final Gen g) { + return Coarbitrary.this.coarbitrary(f.f(b), g); + } + }; + } + + /** + * Co-maps this coarbitrary using the given function. + * + * @param f The function to co-map with. + * @return A co-mapped coarbitrary. + */ + public final Coarbitrary comap(final F f) { + return new Coarbitrary() { + public Gen coarbitrary(final B b, final Gen g) { + return Coarbitrary.this.coarbitrary(f.f(b), g); + } + }; + } + + /** + * A coarbitrary for a function. + * + * @param a An arbitrary for the domain of the function. + * @param c A coarbitrary for the codomain of the function. + * @return A coarbitrary for a function. + */ + public static Coarbitrary> coarbF(final Arbitrary a, final Coarbitrary c) { + return new Coarbitrary>() { + public Gen coarbitrary(final F f, final Gen g) { + return a.gen.bind(new F>() { + public Gen f(final A a) { + return c.coarbitrary(f.f(a), g); + } + }); + } + }; + } + + /** + * A coarbitrary for a function-2. + * + * @param aa An arbitrary for part of the domain of the function. + * @param ab An arbitrary for part of the domain of the function. + * @param c A coarbitrary for the codomain of the function. + * @return A coarbitrary for a function-2. + */ + public static Coarbitrary> coarbF2(final Arbitrary aa, final Arbitrary ab, + final Coarbitrary c) { + return new Coarbitrary>() { + public Gen coarbitrary(final F2 f, final Gen g) { + return coarbF(aa, coarbF(ab, c)).coarbitrary(curry(f), g); + } + }; + } + + /** + * A coarbitrary for a function-3. + * + * @param aa An arbitrary for part of the domain of the function. + * @param ab An arbitrary for part of the domain of the function. + * @param ac An arbitrary for part of the domain of the function. + * @param c A coarbitrary for the codomain of the function. + * @return A coarbitrary for a function-3. + */ + public static Coarbitrary> coarbF3(final Arbitrary aa, final Arbitrary ab, + final Arbitrary ac, final Coarbitrary c) { + return new Coarbitrary>() { + public Gen coarbitrary(final F3 f, final Gen g) { + return coarbF(aa, coarbF(ab, coarbF(ac, c))).coarbitrary(curry(f), g); + } + }; + } + + /** + * A coarbitrary for a function-4. + * + * @param aa An arbitrary for part of the domain of the function. + * @param ab An arbitrary for part of the domain of the function. + * @param ac An arbitrary for part of the domain of the function. + * @param ad An arbitrary for part of the domain of the function. + * @param c A coarbitrary for the codomain of the function. + * @return A coarbitrary for a function-4. + */ + public static Coarbitrary> coarbF4(final Arbitrary aa, final Arbitrary ab, + final Arbitrary ac, final Arbitrary ad, + final Coarbitrary c) { + return new Coarbitrary>() { + public Gen coarbitrary(final F4 f, final Gen g) { + return coarbF(aa, coarbF(ab, coarbF(ac, coarbF(ad, c)))).coarbitrary(curry(f), g); + } + }; + } + + /** + * A coarbitrary for a function-5. + * + * @param aa An arbitrary for part of the domain of the function. + * @param ab An arbitrary for part of the domain of the function. + * @param ac An arbitrary for part of the domain of the function. + * @param ad An arbitrary for part of the domain of the function. + * @param ae An arbitrary for part of the domain of the function. + * @param c A coarbitrary for the codomain of the function. + * @return A coarbitrary for a function-5. + */ + public static Coarbitrary> coarbF5(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Coarbitrary c) { + return new Coarbitrary>() { + public Gen coarbitrary(final F5 f, final Gen g) { + return coarbF(aa, coarbF(ab, coarbF(ac, coarbF(ad, coarbF(ae, c))))).coarbitrary(curry(f), g); + } + }; + } + + /** + * A coarbitrary for a function-6. + * + * @param aa An arbitrary for part of the domain of the function. + * @param ab An arbitrary for part of the domain of the function. + * @param ac An arbitrary for part of the domain of the function. + * @param ad An arbitrary for part of the domain of the function. + * @param ae An arbitrary for part of the domain of the function. + * @param af An arbitrary for part of the domain of the function. + * @param c A coarbitrary for the codomain of the function. + * @return A coarbitrary for a function-6. + */ + public static Coarbitrary> coarbF6(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Coarbitrary c) { + return new Coarbitrary>() { + public Gen coarbitrary(final F6 f, final Gen g) { + return coarbF(aa, coarbF(ab, coarbF(ac, coarbF(ad, coarbF(ae, coarbF(af, c)))))).coarbitrary(curry(f), g); + } + }; + } + + /** + * A coarbitrary for a function-7. + * + * @param aa An arbitrary for part of the domain of the function. + * @param ab An arbitrary for part of the domain of the function. + * @param ac An arbitrary for part of the domain of the function. + * @param ad An arbitrary for part of the domain of the function. + * @param ae An arbitrary for part of the domain of the function. + * @param af An arbitrary for part of the domain of the function. + * @param ag An arbitrary for part of the domain of the function. + * @param c A coarbitrary for the codomain of the function. + * @return A coarbitrary for a function-7. + */ + public static Coarbitrary> coarbF7(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Arbitrary ag, + final Coarbitrary c) { + return new Coarbitrary>() { + public Gen coarbitrary(final F7 f, final Gen g) { + return coarbF(aa, coarbF(ab, coarbF(ac, coarbF(ad, coarbF(ae, coarbF(af, coarbF(ag, c))))))) + .coarbitrary(curry(f), g); + } + }; + } + + /** + * A coarbitrary for a function-8. + * + * @param aa An arbitrary for part of the domain of the function. + * @param ab An arbitrary for part of the domain of the function. + * @param ac An arbitrary for part of the domain of the function. + * @param ad An arbitrary for part of the domain of the function. + * @param ae An arbitrary for part of the domain of the function. + * @param af An arbitrary for part of the domain of the function. + * @param ag An arbitrary for part of the domain of the function. + * @param ah An arbitrary for part of the domain of the function. + * @param c A coarbitrary for the codomain of the function. + * @return A coarbitrary for a function-8. + */ + public static Coarbitrary> coarbF8(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Arbitrary ag, + final Arbitrary ah, + final Coarbitrary c) { + return new Coarbitrary>() { + public Gen coarbitrary(final F8 f, final Gen g) { + return coarbF(aa, coarbF(ab, coarbF(ac, coarbF(ad, coarbF(ae, coarbF(af, coarbF(ag, coarbF(ah, c)))))))) + .coarbitrary(curry(f), g); + } + }; + } + + /** + * A coarbitrary for booleans. + */ + public static final Coarbitrary coarbBoolean = new Coarbitrary() { + public Gen coarbitrary(final Boolean b, final Gen g) { + return variant(b ? 0 : 1, g); + } + }; + + /** + * A coarbitrary for integers. + */ + public static final Coarbitrary coarbInteger = new Coarbitrary() { + public Gen coarbitrary(final Integer i, final Gen g) { + return variant(i >= 0 ? 2 * i : -2 * i + 1, g); + } + }; + + /** + * A coarbitrary for bytes. + */ + public static final Coarbitrary coarbByte = new Coarbitrary() { + public Gen coarbitrary(final Byte b, final Gen g) { + return variant(b >= 0 ? 2 * b : -2 * b + 1, g); + } + }; + + /** + * A coarbitrary for shorts. + */ + public static final Coarbitrary coarbShort = new Coarbitrary() { + public Gen coarbitrary(final Short s, final Gen g) { + return variant(s >= 0 ? 2 * s : -2 * s + 1, g); + } + }; + + /** + * A coarbitrary for longs. + */ + public static final Coarbitrary coarbLong = new Coarbitrary() { + public Gen coarbitrary(final Long l, final Gen g) { + return variant(l >= 0L ? 2L * l : -2L * l + 1L, g); + } + }; + + /** + * A coarbitrary for characters. + */ + public static final Coarbitrary coarbCharacter = new Coarbitrary() { + public Gen coarbitrary(final Character c, final Gen g) { + return variant(c << 1, g); + } + }; + + /** + * A coarbitrary for floats. + */ + public static final Coarbitrary coarbFloat = new Coarbitrary() { + public Gen coarbitrary(final Float f, final Gen g) { + return coarbInteger.coarbitrary(floatToRawIntBits(f), g); + } + }; + + /** + * A coarbitrary for doubles. + */ + public static final Coarbitrary coarbDouble = new Coarbitrary() { + public Gen coarbitrary(final Double d, final Gen g) { + return coarbLong.coarbitrary(doubleToRawLongBits(d), g); + } + }; + + /** + * A coarbitrary for the optional value. + * + * @param ca A coarbitrary for the type of the optional value. + * @return A coarbitrary for the optional value. + */ + public static Coarbitrary> coarbOption(final Coarbitrary ca) { + return new Coarbitrary>() { + public Gen coarbitrary(final Option o, final Gen g) { + return o.isNone() ? variant(0, g) : variant(1, ca.coarbitrary(o.some(), g)); + } + }; + } + + /** + * A coarbitrary for the disjoint union. + * + * @param ca A coarbitrary for one side of the disjoint union. + * @param cb A coarbitrary for one side of the disjoint union. + * @return A coarbitrary for the disjoint union. + */ + public static Coarbitrary> coarbEither(final Coarbitrary ca, final Coarbitrary cb) { + return new Coarbitrary>() { + public Gen coarbitrary(final Either e, final Gen g) { + return e.isLeft() ? + variant(0, ca.coarbitrary(e.left().value(), g)) : + variant(1, cb.coarbitrary(e.right().value(), g)); + } + }; + } + + /** + * A coarbitrary for lists. + * + * @param ca A coarbitrary for the elements of the list. + * @return A coarbitrary for lists. + */ + public static Coarbitrary> coarbList(final Coarbitrary ca) { + return new Coarbitrary>() { + public Gen coarbitrary(final List as, final Gen g) { + return as.isEmpty() ? + variant(0, g) : + variant(1, ca.coarbitrary(as.head(), coarbitrary(as.tail(), g))); + } + }; + } + + /** + * A coarbitrary for strings. + */ + public static final Coarbitrary coarbString = new Coarbitrary() { + public Gen coarbitrary(final String s, final Gen g) { + return coarbList(coarbCharacter).coarbitrary(fromString(s), g); + } + }; + + /** + * A coarbitrary for string buffers. + */ + public static final Coarbitrary coarbStringBuffer = new Coarbitrary() { + public Gen coarbitrary(final StringBuffer s, final Gen g) { + return coarbString.coarbitrary(s.toString(), g); + } + }; + + /** + * A coarbitrary for string builders. + */ + public static final Coarbitrary coarbStringBuilder = new Coarbitrary() { + public Gen coarbitrary(final StringBuilder s, final Gen g) { + return coarbString.coarbitrary(s.toString(), g); + } + }; + + /** + * A coarbitrary for streams. + * + * @param ca A coarbitrary for the elements of the stream. + * @return A coarbitrary for streams. + */ + public static Coarbitrary> coarbStream(final Coarbitrary ca) { + return new Coarbitrary>() { + public Gen coarbitrary(final Stream as, final Gen g) { + return as.isEmpty() ? + variant(0, g) : + variant(1, ca.coarbitrary(as.head(), coarbitrary(as.tail()._1(), g))); + } + }; + } + + /** + * A coarbitrary for the provided LcgRng + * @return A coarbitrary for the provided LcgRng. + */ + public static Coarbitrary coarbLcgRng() { + return new Coarbitrary() { + @Override + public Gen coarbitrary(LcgRng rng, Gen g) { + long i = rng.getSeed(); + return variant(i >= 0 ? 2 * i : -2 * i + 1, g); + } + }; + } + + /** + * A coarbitrary for state. + */ + public static Coarbitrary> coarbState(Arbitrary as, F2 f) { + return new Coarbitrary>() { + @Override + public Gen coarbitrary(State s1, Gen g) { + return as.gen.bind(r -> { + P2 p = s1.run(r); + return variant(f.f(p._1(), p._2()), g); + }); + } + }; + } + + /** + * A coarbitrary for arrays. + * + * @param ca A coarbitrary for the elements of the array. + * @return A coarbitrary for arrays. + */ + public static Coarbitrary> coarbArray(final Coarbitrary ca) { + return new Coarbitrary>() { + public Gen coarbitrary(final Array as, final Gen g) { + return coarbList(ca).coarbitrary(as.toList(), g); + } + }; + } + + /** + * A coarbitrary for throwables. + * + * @param cs A coarbitrary for the throwable message. + * @return A coarbitrary for throwables. + */ + public static Coarbitrary coarbThrowable(final Coarbitrary cs) { + return cs.comap(new F() { + public String f(final Throwable t) { + return t.getMessage(); + } + }); + } + + /** + * A coarbitrary for throwables. + */ + public static final Coarbitrary coarbThrowable = + coarbThrowable(coarbString); + + // BEGIN java.util + + /** + * A coarbitrary for array lists. + * + * @param ca A coarbitrary for the elements of the array list. + * @return A coarbitrary for array lists. + */ + public static Coarbitrary> coarbArrayList(final Coarbitrary ca) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final ArrayList as, final Gen g) { + return coarbArray(ca).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + /** + * A coarbitrary for bit sets. + */ + public static final Coarbitrary coarbBitSet = new Coarbitrary() { + public Gen coarbitrary(final BitSet s, final Gen g) { + List x = nil(); + + for (int i = 0; i < s.size(); i++) { + x = x.snoc(s.get(i)); + } + + return coarbList(coarbBoolean).coarbitrary(x, g); + } + }; + + /** + * A coarbitrary for calendars. + */ + public static final Coarbitrary coarbCalendar = new Coarbitrary() { + public Gen coarbitrary(final Calendar c, final Gen g) { + return coarbLong.coarbitrary(c.getTime().getTime(), g); + } + }; + + /** + * A coarbitrary for dates. + */ + public static final Coarbitrary coarbDate = new Coarbitrary() { + public Gen coarbitrary(final Date d, final Gen g) { + return coarbLong.coarbitrary(d.getTime(), g); + } + }; + + /** + * A coarbitrary for enum maps. + * + * @param ck A coarbitrary for the map keys. + * @param cv A coarbitrary for the map values. + * @return A coarbitrary for enum maps. + */ + public static , V> Coarbitrary> coarbEnumMap(final Coarbitrary ck, + final Coarbitrary cv) { + return new Coarbitrary>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Gen coarbitrary(final EnumMap m, final Gen g) { + return coarbHashtable(ck, cv).coarbitrary(new Hashtable(m), g); + } + }; + } + + /** + * A coarbitrary for enum sets. + * + * @param c A coarbitrary for the elements of the enum set. + * @return A coarbitrary for enum sets. + */ + public static > Coarbitrary> coarbEnumSet(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final EnumSet as, final Gen g) { + return coarbHashSet(c).coarbitrary(new HashSet(as), g); + } + }; + } + + /** + * A coarbitrary for gregorian calendars. + */ + public static final Coarbitrary coarbGregorianCalendar = new Coarbitrary() { + public Gen coarbitrary(final GregorianCalendar c, final Gen g) { + return coarbLong.coarbitrary(c.getTime().getTime(), g); + } + }; + + /** + * A coarbitrary for hash maps. + * + * @param ck A coarbitrary for the map keys. + * @param cv A coarbitrary for the map values. + * @return A coarbitrary for hash maps. + */ + public static Coarbitrary> coarbHashMap(final Coarbitrary ck, final Coarbitrary cv) { + return new Coarbitrary>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Gen coarbitrary(final HashMap m, final Gen g) { + return coarbHashtable(ck, cv).coarbitrary(new Hashtable(m), g); + } + }; + } + + /** + * A coarbitrary for hash sets. + * + * @param c A coarbitrary for the elements of the hash set. + * @return A coarbitrary for hash sets. + */ + public static Coarbitrary> coarbHashSet(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final HashSet as, final Gen g) { + return coarbArray(c).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + /** + * A coarbitrary for hash tables. + * + * @param ck A coarbitrary for the map keys. + * @param cv A coarbitrary for the map values. + * @return A coarbitrary for hash tables. + */ + public static Coarbitrary> coarbHashtable(final Coarbitrary ck, final Coarbitrary cv) { + return new Coarbitrary>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Gen coarbitrary(final Hashtable h, final Gen g) { + List> x = nil(); + + for (final K k : h.keySet()) { + x = x.snoc(p(k, h.get(k))); + } + + return coarbList(coarbP2(ck, cv)).coarbitrary(x, g); + } + }; + } + + /** + * A coarbitrary for identity hash maps. + * + * @param ck A coarbitrary for the map keys. + * @param cv A coarbitrary for the map values. + * @return A coarbitrary for identity hash maps. + */ + public static Coarbitrary> coarbIdentityHashMap(final Coarbitrary ck, + final Coarbitrary cv) { + return new Coarbitrary>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Gen coarbitrary(final IdentityHashMap m, final Gen g) { + return coarbHashtable(ck, cv).coarbitrary(new Hashtable(m), g); + } + }; + } + + /** + * A coarbitrary for linked hash maps. + * + * @param ck A coarbitrary for the map keys. + * @param cv A coarbitrary for the map values. + * @return A coarbitrary for linked hash maps. + */ + public static Coarbitrary> coarbLinkedHashMap(final Coarbitrary ck, + final Coarbitrary cv) { + return new Coarbitrary>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Gen coarbitrary(final LinkedHashMap m, final Gen g) { + return coarbHashtable(ck, cv).coarbitrary(new Hashtable(m), g); + } + }; + } + + /** + * A coarbitrary for linked hash sets. + * + * @param c A coarbitrary for the elements of the linked hash set. + * @return A coarbitrary for linked hash sets. + */ + public static Coarbitrary> coarbLinkedHashSet(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final LinkedHashSet as, final Gen g) { + return coarbHashSet(c).coarbitrary(new HashSet(as), g); + } + }; + } + + /** + * A coarbitrary for linked lists. + * + * @param c A coarbitrary for the elements of the linked list. + * @return A coarbitrary for linked lists. + */ + public static Coarbitrary> coarbLinkedList(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final LinkedList as, final Gen g) { + return coarbArray(c).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + /** + * A coarbitrary for priority queues. + * + * @param c A coarbitrary for the elements of the priority queue. + * @return A coarbitrary for priority queues. + */ + public static Coarbitrary> coarbPriorityQueue(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final PriorityQueue as, final Gen g) { + return coarbArray(c).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + /** + * A coarbitrary for properties. + */ + public static final Coarbitrary coarbProperties = new Coarbitrary() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Gen coarbitrary(final Properties p, final Gen g) { + final Hashtable t = new Hashtable(); + + for (final Object s : p.keySet()) { + t.put((String) s, p.getProperty((String) s)); + } + + return coarbHashtable(coarbString, coarbString).coarbitrary(t, g); + } + }; + + /** + * A coarbitrary for stacks. + * + * @param c A coarbitrary for the elements of the stack. + * @return A coarbitrary for stacks. + */ + public static Coarbitrary> coarbStack(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final Stack as, final Gen g) { + return coarbArray(c).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + /** + * A coarbitrary for tree maps. + * + * @param ck A coarbitrary for the map keys. + * @param cv A coarbitrary for the map values. + * @return A coarbitrary for tree maps. + */ + public static Coarbitrary> coarbTreeMap(final Coarbitrary ck, final Coarbitrary cv) { + return new Coarbitrary>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Gen coarbitrary(final TreeMap m, final Gen g) { + return coarbHashtable(ck, cv).coarbitrary(new Hashtable(m), g); + } + }; + } + + /** + * A coarbitrary for tree sets. + * + * @param c A coarbitrary for the elements of the tree set. + * @return A coarbitrary for tree sets. + */ + public static Coarbitrary> coarbTreeSet(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final TreeSet as, final Gen g) { + return coarbHashSet(c).coarbitrary(new HashSet(as), g); + } + }; + } + + /** + * A coarbitrary for vectors. + * + * @param c A coarbitrary for the elements of the vector. + * @return A coarbitrary for vectors. + */ + public static Coarbitrary> coarbVector(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked", "UseOfObsoleteCollectionType"}) + public Gen coarbitrary(final Vector as, final Gen g) { + return coarbArray(c).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + /** + * A coarbitrary for weak hash maps. + * + * @param ck A coarbitrary for the map keys. + * @param cv A coarbitrary for the map values. + * @return A coarbitrary for weak hash maps. + */ + public static Coarbitrary> coarbWeakHashMap(final Coarbitrary ck, + final Coarbitrary cv) { + return new Coarbitrary>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Gen coarbitrary(final WeakHashMap m, final Gen g) { + return coarbHashtable(ck, cv).coarbitrary(new Hashtable(m), g); + } + }; + } + + // END java.util + + // BEGIN java.util.concurrent + + /** + * A coarbitrary for array blocking queues. + * + * @param c A coarbitrary for the elements of the array blocking queue. + * @return A coarbitrary for array blocking queues. + */ + public static Coarbitrary> coarbArrayBlockingQueue(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final ArrayBlockingQueue as, final Gen g) { + return coarbArray(c).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + /** + * A coarbitrary for concurrent hash maps. + * + * @param ck A coarbitrary for the map keys. + * @param cv A coarbitrary for the map values. + * @return A coarbitrary for concurrent hash maps. + */ + public static Coarbitrary> coarbConcurrentHashMap(final Coarbitrary ck, + final Coarbitrary cv) { + return new Coarbitrary>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Gen coarbitrary(final ConcurrentHashMap m, final Gen g) { + return coarbHashtable(ck, cv).coarbitrary(new Hashtable(m), g); + } + }; + } + + /** + * A coarbitrary for concurrent linked queues. + * + * @param c A coarbitrary for the elements of the concurrent linked queue. + * @return A coarbitrary for concurrent linked queues. + */ + public static Coarbitrary> coarbConcurrentLinkedQueue(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final ConcurrentLinkedQueue as, final Gen g) { + return coarbArray(c).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + /** + * A coarbitrary for copy-on-write array lists. + * + * @param c A coarbitrary for the elements of the copy-on-write array list. + * @return A coarbitrary for copy-on-write array lists. + */ + public static Coarbitrary> coarbCopyOnWriteArrayList(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final CopyOnWriteArrayList as, final Gen g) { + return coarbArray(c).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + /** + * A coarbitrary for copy-on-write array sets. + * + * @param c A coarbitrary for the elements of the copy-on-write array set. + * @return A coarbitrary for copy-on-write array sets. + */ + public static Coarbitrary> coarbCopyOnWriteArraySet(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final CopyOnWriteArraySet as, final Gen g) { + return coarbArray(c).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + /** + * A coarbitrary for delay queues. + * + * @param c A coarbitrary for the elements of the delay queue. + * @return A coarbitrary for delay queues. + */ + public static Coarbitrary> coarbDelayQueue(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final DelayQueue as, final Gen g) { + return coarbArray(c).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + /** + * A coarbitrary for linked blocking queues. + * + * @param c A coarbitrary for the elements of the linked blocking queue. + * @return A coarbitrary for linked blocking queues. + */ + public static Coarbitrary> coarbLinkedBlockingQueue(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final LinkedBlockingQueue as, final Gen g) { + return coarbArray(c).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + /** + * A coarbitrary for priority blocking queues. + * + * @param c A coarbitrary for the elements of the priority blocking queue. + * @return A coarbitrary for priority blocking queues. + */ + public static Coarbitrary> coarbPriorityBlockingQueue(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final PriorityBlockingQueue as, final Gen g) { + return coarbArray(c).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + /** + * A coarbitrary for synchronous queues. + * + * @param c A coarbitrary for the elements of the synchronous queue. + * @return A coarbitrary for synchronous queues. + */ + public static Coarbitrary> coarbSynchronousQueue(final Coarbitrary c) { + return new Coarbitrary>() { + @SuppressWarnings({"unchecked"}) + public Gen coarbitrary(final SynchronousQueue as, final Gen g) { + return coarbArray(c).coarbitrary(array(as.toArray((A[]) new Object[as.size()])), g); + } + }; + } + + // END java.util.concurrent + + // BEGIN java.sql + + public static final Coarbitrary coarbSQLDate = new Coarbitrary() { + public Gen coarbitrary(final java.sql.Date d, final Gen g) { + return coarbLong.coarbitrary(d.getTime(), g); + } + }; + + public static final Coarbitrary coarbTimestamp = new Coarbitrary() { + public Gen coarbitrary(final Timestamp t, final Gen g) { + return coarbLong.coarbitrary(t.getTime(), g); + } + }; + + public static final Coarbitrary Coarbitrary> coarbP1(final Coarbitrary ca) { + return new Coarbitrary>() { + public Gen coarbitrary(final P1 p, final Gen g) { + return ca.coarbitrary(p._1(), g); + } + }; + } + + /** + * A coarbitrary for product-2 values. + * + * @param ca A coarbitrary for one of the types over which the product-2 is defined. + * @param cb A coarbitrary for one of the types over which the product-2 is defined. + * @return A coarbitrary for product-2 values. + */ + public static Coarbitrary> coarbP2(final Coarbitrary ca, final Coarbitrary cb) { + return new Coarbitrary>() { + public Gen coarbitrary(final P2 p, final Gen g) { + return ca.coarbitrary(p._1(), cb.coarbitrary(p._2(), g)); + } + }; + } + + /** + * A coarbitrary for product-3 values. + * + * @param ca A coarbitrary for one of the types over which the product-3 is defined. + * @param cb A coarbitrary for one of the types over which the product-3 is defined. + * @param cc A coarbitrary for one of the types over which the product-3 is defined. + * @return A coarbitrary for product-3 values. + */ + public static Coarbitrary> coarbP3(final Coarbitrary ca, final Coarbitrary cb, + final Coarbitrary cc) { + return new Coarbitrary>() { + public Gen coarbitrary(final P3 p, final Gen g) { + return ca.coarbitrary(p._1(), cb.coarbitrary(p._2(), cc.coarbitrary(p._3(), g))); + } + }; + } + + /** + * A coarbitrary for product-4 values. + * + * @param ca A coarbitrary for one of the types over which the product-4 is defined. + * @param cb A coarbitrary for one of the types over which the product-4 is defined. + * @param cc A coarbitrary for one of the types over which the product-4 is defined. + * @param cd A coarbitrary for one of the types over which the product-4 is defined. + * @return A coarbitrary for product-4 values. + */ + public static Coarbitrary> coarbP4(final Coarbitrary ca, final Coarbitrary cb, + final Coarbitrary cc, final Coarbitrary cd) { + return new Coarbitrary>() { + public Gen coarbitrary(final P4 p, final Gen g) { + return ca.coarbitrary(p._1(), cb.coarbitrary(p._2(), cc.coarbitrary(p._3(), cd.coarbitrary(p._4(), g)))); + } + }; + } + + /** + * A coarbitrary for product-5 values. + * + * @param ca A coarbitrary for one of the types over which the product-5 is defined. + * @param cb A coarbitrary for one of the types over which the product-5 is defined. + * @param cc A coarbitrary for one of the types over which the product-5 is defined. + * @param cd A coarbitrary for one of the types over which the product-5 is defined. + * @param ce A coarbitrary for one of the types over which the product-5 is defined. + * @return A coarbitrary for product-5 values. + */ + public static Coarbitrary> coarbP5(final Coarbitrary ca, final Coarbitrary cb, + final Coarbitrary cc, final Coarbitrary cd, + final Coarbitrary ce) { + return new Coarbitrary>() { + public Gen coarbitrary(final P5 p, final Gen g) { + return ca.coarbitrary(p._1(), + cb.coarbitrary(p._2(), cc.coarbitrary(p._3(), cd.coarbitrary(p._4(), ce.coarbitrary(p._5(), g))))); + } + }; + } + + /** + * A coarbitrary for product-6 values. + * + * @param ca A coarbitrary for one of the types over which the product-6 is defined. + * @param cb A coarbitrary for one of the types over which the product-6 is defined. + * @param cc A coarbitrary for one of the types over which the product-6 is defined. + * @param cd A coarbitrary for one of the types over which the product-6 is defined. + * @param ce A coarbitrary for one of the types over which the product-6 is defined. + * @param cf A coarbitrary for one of the types over which the product-6 is defined. + * @return A coarbitrary for product-6 values. + */ + public static Coarbitrary> coarbP6(final Coarbitrary ca, + final Coarbitrary cb, + final Coarbitrary cc, + final Coarbitrary cd, + final Coarbitrary ce, + final Coarbitrary cf) { + return new Coarbitrary>() { + public Gen coarbitrary(final P6 p, final Gen g) { + return ca.coarbitrary(p._1(), cb.coarbitrary(p._2(), + cc.coarbitrary(p._3(), cd.coarbitrary(p._4(), ce.coarbitrary(p._5(), cf.coarbitrary(p._6(), g)))))); + } + }; + } + + /** + * A coarbitrary for product-7 values. + * + * @param ca A coarbitrary for one of the types over which the product-7 is defined. + * @param cb A coarbitrary for one of the types over which the product-7 is defined. + * @param cc A coarbitrary for one of the types over which the product-7 is defined. + * @param cd A coarbitrary for one of the types over which the product-7 is defined. + * @param ce A coarbitrary for one of the types over which the product-7 is defined. + * @param cf A coarbitrary for one of the types over which the product-7 is defined. + * @param cg A coarbitrary for one of the types over which the product-7 is defined. + * @return A coarbitrary for product-7 values. + */ + public static Coarbitrary> coarbP7(final Coarbitrary ca, + final Coarbitrary cb, + final Coarbitrary cc, + final Coarbitrary cd, + final Coarbitrary ce, + final Coarbitrary cf, + final Coarbitrary cg) { + return new Coarbitrary>() { + public Gen coarbitrary(final P7 p, final Gen g) { + return ca.coarbitrary(p._1(), cb.coarbitrary(p._2(), cc.coarbitrary(p._3(), + cd.coarbitrary(p._4(), ce.coarbitrary(p._5(), cf.coarbitrary(p._6(), cg.coarbitrary(p._7(), g))))))); + } + }; + } + + /** + * A coarbitrary for product-8 values. + * + * @param ca A coarbitrary for one of the types over which the product-8 is defined. + * @param cb A coarbitrary for one of the types over which the product-8 is defined. + * @param cc A coarbitrary for one of the types over which the product-8 is defined. + * @param cd A coarbitrary for one of the types over which the product-8 is defined. + * @param ce A coarbitrary for one of the types over which the product-8 is defined. + * @param cf A coarbitrary for one of the types over which the product-8 is defined. + * @param cg A coarbitrary for one of the types over which the product-8 is defined. + * @param ch A coarbitrary for one of the types over which the product-8 is defined. + * @return A coarbitrary for product-8 values. + */ + public static Coarbitrary> coarbP8(final Coarbitrary ca, + final Coarbitrary cb, + final Coarbitrary cc, + final Coarbitrary cd, + final Coarbitrary ce, + final Coarbitrary cf, + final Coarbitrary cg, + final Coarbitrary ch) { + return new Coarbitrary>() { + public Gen coarbitrary(final P8 p, final Gen g) { + return ca.coarbitrary(p._1(), cb.coarbitrary(p._2(), cc.coarbitrary(p._3(), cd.coarbitrary(p._4(), + ce.coarbitrary(p._5(), cf.coarbitrary(p._6(), cg.coarbitrary(p._7(), ch.coarbitrary(p._8(), g)))))))); + } + }; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/Gen.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/Gen.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,652 @@ +package fj.test; + +import static fj.Bottom.error; +import fj.Effect; +import fj.F; +import fj.Function; +import static fj.Function.flip; +import static fj.Function.curry; +import fj.P2; +import static fj.P2.__1; +import fj.Unit; +import fj.F2; +import static fj.data.Array.array; +import fj.data.List; +import static fj.data.List.nil; +import static fj.data.List.replicate; +import fj.data.Option; +import fj.function.Effect1; + +import static fj.Monoid.intAdditionMonoid; +import static fj.Ord.intOrd; + +import static java.lang.Math.max; +import static java.lang.Math.min; + +/** + *

A generator for values of the type of the given type parameter (A). Generation + * of a value accepts a general 'size' argument (integer), a {@link Rand random generator} and + * returns an {@link Option optional value} of the type parameter. Several generators are provided, + * allowing various forms of composition of generators.

A user typically creates an {@link + * Arbitrary arbitrary} to return a generator using the 'combinator methods' below. For example, + * suppose a class Person: +

+class Person {
+  final int age;
+  final String name;
+  final boolean male;
+
+  Person(final int age, final String name, final boolean male) {
+    this.age = age;
+    this.name = name;
+    this.male = male;
+  }
+}
+
+ *

In a case like this one, a user may create a generator over Person by + * invoking the {@link #bind(F)} methods — in this case, {@link #bind(Gen , Gen , F)} the one + * that takes two generator arguments}, since the class has one more than two fields (the bind + * method is invoked on a generator adding the extra one to the count as they are composed). The + * class fields are of types for which there exist generators (on {@link Arbitrary} so those can be + * used to compose a generator for Person:

+
+static Arbitrary<Person> personArbitrary() {
+  final Gen<Person> personGenerator = arbInteger.gen.bind(arbString().gen, arbBoolean().gen,
+      // compose the generators
+      {int age => {String name => {boolean male => new Person(age, name, male)}}};
+  return arbitrary(personGenerator);
+}
+
+ *

+ * The example above uses Java 7 closure syntax. Here is the same example using objects instead: +

+static Arbitrary<Person> personArbitrary() {
+  final Gen<Person> personGenerator = arbInteger.gen.bind(arbString.gen, arbBoolean.gen,
+      // compose the generators
+      new F<Integer, F<String, F<Boolean, Person>>>() {
+        public F<String, F<Boolean, Person>> f(final Integer age) {
+          return new F<String, F<Boolean, Person>>() {
+            public F<Boolean, Person> f(final String name) {
+              return new F<Boolean, Person>() {
+                public Person f(final Boolean male) {
+                  return new Person(age, name, male);
+                }
+              };
+            }
+          };
+        }
+      });
+  return arbitrary(personGenerator);
+}
+
+ * + * @version %build.number% + */ +public final class Gen
{ + private final F> f; + + private Gen(final F> f) { + this.f = f; + } + + /** + * Applies the given size and random generator to produce a value. + * + * @param i The size to use to produce the value. + * @param r The random generator to use to produce the value.. + * @return A generated value. + */ + public A gen(final int i, final Rand r) { + return f.f(i).f(r); + } + + /** + * Maps the given function across this generator. + * + * @param f The function to map across this generator. + * @return A new generator after applying the mapping function. + */ + public Gen map(final F f) { + return new Gen(new F>() { + public F f(final Integer i) { + return new F() { + public B f(final Rand r) { + return f.f(gen(i, r)); + } + }; + } + }); + } + + /** + * Returns a generator that produces values that meet the given predicate. + * + * @param f The predicate to meet for the values produced by the generator. + * @return A generator that produces values that meet the given predicate. + */ + public Gen filter(final F f) { + return gen(curry(new F2() { + public A f(final Integer i, final Rand r) { + A a; + + do { + a = gen(i, r); + } while(!f.f(a)); + + return a; + } + })); + } + + /** + * Executes a side-effect for each generated result using the given arguments. + * + * @param i The size to generate the result to apply the side-effect to. + * @param r The random generator to generate the result to apply the side-effect to. + * @param f The side-effect to execute on the generated value. + * @return The unit value. + */ + public Unit foreach(final Integer i, final Rand r, final F f) { + return f.f(this.f.f(i).f(r)); + } + + /** + * Executes a side-effect for each generated result using the given arguments. + * + * @param i The size to generate the result to apply the side-effect to. + * @param r The random generator to generate the result to apply the side-effect to. + * @param f The side-effect to execute on the generated value. + */ + public void foreachDoEffect(final Integer i, final Rand r, final Effect1 f) { + f.f(this.f.f(i).f(r)); + } + + /** + * Binds the given function across this generator to produce a new generator. + * + * @param f The function to bind across this generator. + * @return A new generator after binding the given function. + */ + public Gen bind(final F> f) { + return new Gen(new F>() { + public F f(final Integer i) { + return new F() { + public B f(final Rand r) { + return f.f(gen(i, r)).f.f(i).f(r); + } + }; + } + }); + } + + /** + * Binds the given function across this generator and the given generator to produce a new + * generator. + * + * @param gb The second generator to bind the given function across. + * @param f The function to bind across this generator and the given generator. + * @return A new generator after binding the given function. + */ + public Gen bind(final Gen gb, final F> f) { + return gb.apply(map(f)); + } + + /** + * Binds the given function across this generator and the given generators to produce a new + * generator. + * + * @param gb The second generator to bind the given function across. + * @param gc The third generator to bind the given function across. + * @param f The function to bind across this generator and the given generators. + * @return A new generator after binding the given function. + */ + public Gen bind(final Gen gb, final Gen gc, final F>> f) { + return gc.apply(bind(gb, f)); + } + + /** + * Binds the given function across this generator and the given generators to produce a new + * generator. + * + * @param gb The second generator to bind the given function across. + * @param gc The third generator to bind the given function across. + * @param gd The fourth generator to bind the given function across. + * @param f The function to bind across this generator and the given generators. + * @return A new generator after binding the given function. + */ + public Gen bind(final Gen gb, final Gen gc, final Gen gd, final F>>> f) { + return gd.apply(bind(gb, gc, f)); + } + + /** + * Binds the given function across this generator and the given generators to produce a new + * generator. + * + * @param gb The second generator to bind the given function across. + * @param gc The third generator to bind the given function across. + * @param gd The fourth generator to bind the given function across. + * @param ge The fifth generator to bind the given function across. + * @param f The function to bind across this generator and the given generators. + * @return A new generator after binding the given function. + */ + public Gen bind(final Gen gb, final Gen gc, final Gen gd, final Gen ge, final F>>>> f) { + return ge.apply(bind(gb, gc, gd, f)); + } + + /** + * Binds the given function across this generator and the given generators to produce a new + * generator. + * + * @param gb The second generator to bind the given function across. + * @param gc The third generator to bind the given function across. + * @param gd The fourth generator to bind the given function across. + * @param ge The fifth generator to bind the given function across. + * @param gf The sixth generator to bind the given function across. + * @param f The function to bind across this generator and the given generators. + * @return A new generator after binding the given function. + */ + public Gen bind(final Gen gb, final Gen gc, final Gen gd, final Gen ge, final Gen gf, final F>>>>> f) { + return gf.apply(bind(gb, gc, gd, ge, f)); + } + + /** + * Binds the given function across this generator and the given generators to produce a new + * generator. + * + * @param gb The second generator to bind the given function across. + * @param gc The third generator to bind the given function across. + * @param gd The fourth generator to bind the given function across. + * @param ge The fifth generator to bind the given function across. + * @param gf The sixth generator to bind the given function across. + * @param gg The seventh generator to bind the given function across. + * @param f The function to bind across this generator and the given generators. + * @return A new generator after binding the given function. + */ + public Gen bind(final Gen gb, final Gen gc, final Gen gd, final Gen ge, final Gen gf, final Gen gg, final F>>>>>> f) { + return gg.apply(bind(gb, gc, gd, ge, gf, f)); + } + + /** + * Binds the given function across this generator and the given generators to produce a new + * generator. + * + * @param gb The second generator to bind the given function across. + * @param gc The third generator to bind the given function across. + * @param gd The fourth generator to bind the given function across. + * @param ge The fifth generator to bind the given function across. + * @param gf The sixth generator to bind the given function across. + * @param gg The seventh generator to bind the given function across. + * @param gh The eighth generator to bind the given function across. + * @param f The function to bind across this generator and the given generators. + * @return A new generator after binding the given function. + */ + public Gen bind(final Gen gb, final Gen gc, final Gen gd, final Gen ge, final Gen gf, final Gen gg, final Gen gh, final F>>>>>>> f) { + return gh.apply(bind(gb, gc, gd, ge, gf, gg, f)); + } + + /** + * Function application within this generator to produce a new generator. + * + * @param gf The generator over the function to apply to this generator. + * @return A new generator after function application. + */ + public Gen apply(final Gen> gf) { + return gf.bind(new F, Gen>() { + public Gen f(final F f) { + return map(new F() { + public B f(final A a) { + return f.f(a); + } + }); + } + }); + } + + /** + * Resizes this generator with the given size. + * + * @param s The new size of the generator. + * @return A new generator that uses the given size. + */ + public Gen resize(final int s) { + return new Gen(new F>() { + public F f(final Integer i) { + return new F() { + public A f(final Rand r) { + return f.f(s).f(r); + } + }; + } + }); + } + + /** + * Returns a generator that uses the given function. + * + * @param f The function to use for this generator. + * @return A new generator that uses the given function. + */ + public static Gen gen(final F> f) { + return new Gen(f); + } + + /** + * Sequence the given generators through a {@link #bind(F)} operation. + * + * @param gs The generators to sequence. + * @return A generator of lists after sequencing the given generators. + */ + public static Gen> sequence(final List> gs) { + return gs.foldRight(new F, F>, Gen>>>() { + public F>, Gen>> f(final Gen ga) { + return new F>, Gen>>() { + public Gen> f(final Gen> gas) { + return ga.bind(gas, List.cons()); + } + }; + } + }, value(List.nil())); + } + + /** + * Sequences the given generator the given number of times through a {@link #bind(F)} operation. + * + * @param n The number of times to sequence the given generator. + * @param g The generator sequence. + * @return A generator of lists after sequencing the given generator. + */ + public static Gen> sequenceN(final int n, final Gen g) { + return sequence(replicate(n, g)); + } + + /** + * Constructs a generator that can access its construction arguments — size and random + * generator. + * + * @param f The function that constructs the generator with its arguments. + * @return A new generator. + */ + public static Gen parameterised(final F>> f) { + return new Gen(curry(new F2() { + public A f(final Integer i, final Rand r) { + return f.f(i).f(r).gen(i, r); + } + })); + } + + /** + * Constructs a generator that can access its size construction arguments. + * + * @param f The function that constructs the generator with its size argument. + * @return A new generator. + */ + public static Gen sized(final F> f) { + return parameterised(flip(Function.>>constant(f))); + } + + /** + * Returns a generator that always produces the given value. + * + * @param a The value to always produce. + * @return A generator that always produces the given value. + */ + public static Gen value(final A a) { + return new Gen(new F>() { + public F f(final Integer i) { + return new F() { + public A f(final Rand r) { + return a; + } + }; + } + }); + } + + /** + * Returns a generator that produces values between the given range (inclusive). + * + * @param from The value for the generator to produce values from. + * @param to The value for the generator to produce values from. + * @return A generator that produces values between the given range (inclusive). + */ + public static Gen choose(final int from, final int to) { + final int f = min(from, to); + final int t = max(from, to); + return parameterised(curry(new F2>() { + public Gen f(final Integer i, final Rand r) { + return value(r.choose(f, t)); + } + })); + } + + /** + * Returns a generator that produces values between the given range (inclusive). + * + * @param from The value for the generator to produce values from. + * @param to The value for the generator to produce values from. + * @return A generator that produces v + */ + public static Gen choose(final double from, final double to) { + final double f = min(from, to); + final double t = max(from, to); + return parameterised(new F>>() { + public F> f(final Integer i) { + return new F>() { + public Gen f(final Rand r) { + return value(r.choose(f, t)); + } + }; + } + }); + } + + /** + * Returns a generator that never returns a value. + * + * @return A generator that never returns a value. + */ + public static Gen fail() { + return new Gen(new F>() { + public F f(final Integer i) { + return new F() { + public A f(final Rand r) { + throw error("Failing generator"); + } + }; + } + }); + } + + /** + * Joins the generator of generators through a {@link #bind(F)} operation. + * + * @param g The generator of generators to join. + * @return A new generator after joining the given generator. + */ + public static Gen join(final Gen> g) { + return g.bind(Function.>identity()); + } + + /** + * Returns a generator that uses values from the given frequency and generator pairs. The returned + * generator will produce values from the generator in a pair with a higher frequency than a lower + * frequency generator. + * + * @param gs The pairs of frequency and generator from which to return values in the returned + * generator. + * @return A new generator that uses the given pairs of frequency and generator. + */ + public static Gen frequency(final List>> gs) { + final class Pick { + Gen pick(final int n, final List>> gs) { + if(gs.isEmpty()) + return fail(); + else { + final int k = gs.head()._1(); + return n <= k ? gs.head()._2() : pick(n - k, gs.tail()); + } + } + } + + final F>, Integer> f = __1(); + + return choose(1, intAdditionMonoid.sumLeft(gs.map(f))).bind(new F>() { + public Gen f(final Integer i) { + return new Pick().pick(i, gs); + } + }); + } + + /** + * Returns a generator that produces values from the given frequency and value pairs. The returned + * generator will produce the value with a higher frequency than a lower one. + * + * @param as The pairs of frequency and value from which to produce values. + * @return A new generator that uses the given pairs of frequency and value. + */ + public static Gen elemFrequency(final List> as) { + return frequency(as.map(new F, P2>>() { + public P2> f(final P2 p) { + return p.map2(new F>() { + public Gen f(final A a) { + return value(a); + } + }); + } + })); + } + + /** + * Returns a generator that produces values from the given arguments. + * + * @param as The values that the returned generator may produce. + * @return A generator that produces values from the given arguments. + */ + public static Gen elements(final A... as) { + return array(as).isEmpty() ? Gen.fail() : choose(0, as.length - 1).map(new F() { + public A f(final Integer i) { + return as[i]; + } + }); + } + + /** + * Returns a generator that produces values from one of the given generators on subsequent + * requests. + * + * @param gs The list of generators to produce a value from. + * @return A generator that produces values from one of the given generators on subsequent + * requests. + */ + public static Gen oneOf(final List> gs) { + return gs.isEmpty() ? Gen.fail() : choose(0, gs.length() - 1).bind(new F>() { + public Gen f(final Integer i) { + return gs.index(i); + } + }); + } + + /** + * Returns a generator of lists whose values come from the given generator. + * + * @param g The generator to produce values from for the returned generator. + * @param x An adjuster of size to apply to the given generator when producing values. + * @return A generator of lists whose values come from the given generator. + */ + public static Gen> listOf(final Gen g, final int x) { + return sized(new F>>() { + public Gen> f(final Integer size) { + return choose(x, size).bind(new F>>() { + public Gen> f(final Integer n) { + return sequenceN(n, g); + } + }); + } + }); + } + + /** + * Returns a generator of lists whose values come from the given generator. + * + * @param g The generator to produce values from for the returned generator. + * @return A generator of lists whose values come from the given generator. + */ + public static Gen> listOf(final Gen g) { + return listOf(g, 0); + } + + /** + * Returns a generator of lists whose values come from the given generator. + * + * @param g The generator to produce values from for the returned generator. + * @return A generator of lists whose values come from the given generator. + */ + public static Gen> listOf1(final Gen g) { + return listOf(g, 1); + } + + /** + * Returns a generator of lists that picks the given number of elements from the given list. If + * the given number is less than zero or greater than the length of the given list, then the + * returned generator will never produce a value. + * + * @param n The number of elements to pick from the given list. + * @param as The list from which to pick elements. + * @return A generator of lists that picks the given number of elements from the given list. + */ + public static Gen> pick(final int n, final List as) { + return n < 0 || n > as.length() ? Gen.>fail() : sequenceN(n, choose(0, as.length() - 1)).map(new F, List>() { + public List f(final List is) { + List r = nil(); + + List iis = is.sort(intOrd); + List> aas = as.zipIndex(); + + //noinspection ForLoopWithMissingComponent + for(; iis.isNotEmpty() && aas.isNotEmpty(); aas = aas.tail()) + if(iis.head().equals(aas.head()._2())) + iis = iis.tail(); + else + r = r.snoc(aas.head()._1()); + + return r; + } + }); + } + + /** + * Returns a generator of lists that produces some of the values of the given list. + * + * @param as The list from which to pick values. + * @return A generator of lists that produces some of the values of the given list. + */ + public static Gen> someOf(final List as) { + return choose(0, as.length()).bind(new F>>() { + public Gen> f(final Integer i) { + return pick(i, as); + } + }); + } + + /** + * Promotes the given function to a generator for functions. + * + * @param f The function to promote to a generator of functions. + * @return A generator for functions. + */ + public static Gen> promote(final F> f) { + return new Gen>(new F>>() { + public F> f(final Integer i) { + return new F>() { + public F f(final Rand r) { + return new F() { + public B f(final A a) { + return f.f(a).f.f(i).f(r); + } + }; + } + }; + } + }); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/Property.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/Property.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,1661 @@ +package fj.test; + +import static fj.Function.curry; +import static fj.Function.compose2; +import static fj.P.p; + +import fj.*; + +import static fj.P2.__2; +import fj.data.List; +import fj.data.Option; +import static fj.data.Option.none; +import fj.data.Stream; +import static fj.test.Arg.arg; +import static fj.test.CheckResult.exhausted; +import static fj.test.CheckResult.falsified; +import static fj.test.CheckResult.genException; +import static fj.test.CheckResult.passed; +import static fj.test.CheckResult.propException; +import static fj.test.CheckResult.proven; +import static fj.test.Result.noResult; +import static java.lang.Math.round; + +/** + * Represents an algebraic property about a program that may be {@link #check(Rand, int, int, int, + * int) checked} for its truth value. For example, it is true that "for all integers (call it x) and + * for all integers (call it y), then x + y is equivalent to y + x". This statement is a (algebraic) + * property, proposition or theorem that, when checked, will at least (depending on arguments) fail + * to be falsified — since there does not exist a counter-example to this statement. + * + * @version %build.number% + */ +public final class Property { + private final F> f; + + private Property(final F> f) { + this.f = f; + } + + /** + * Returns the result of applying the given size and random generator. + * + * @param i The size to use to obtain a result. + * @param r The random generator to use to obtain a result. + * @return The result of applying the given size and random generator. + */ + public Result prop(final int i, final Rand r) { + return f.f(i).f(r); + } + + /** + * Returns a generator of results from this property. + * + * @return A generator of results from this property. + */ + public Gen gen() { + return Gen.gen(new F>() { + public F f(final Integer i) { + return new F() { + public Result f(final Rand r) { + return f.f(i).f(r); + } + }; + } + }); + } + + /** + * Performs a conjunction of this property with the given property. + * + * @param p The property to perform the conjunction with. + * @return A conjunction of this property with the given property. + */ + public Property and(final Property p) { + return fromGen(gen().bind(p.gen(), new F>() { + public F f(final Result res1) { + return new F() { + public Result f(final Result res2) { + return res1.isException() || res1.isFalsified() ? res1 : res2.isException() || res2.isFalsified() ? res2 : res1.isProven() || res1.isUnfalsified() ? res2 : res2.isProven() || res2.isUnfalsified() ? res1 : noResult(); + } + }; + } + })); + } + + /** + * Performs a disjunction of this property with the given property. + * + * @param p The property to perform the disjunction with. + * @return A disjunction of this property with the given property. + */ + public Property or(final Property p) { + return fromGen(gen().bind(p.gen(), new F>() { + public F f(final Result res1) { + return new F() { + public Result f(final Result res2) { + return res1.isException() || res1.isFalsified() ? res1 : res2.isException() || res2.isFalsified() ? res2 : res1.isProven() || res1.isUnfalsified() ? res1 : res2.isProven() || res2.isUnfalsified() ? res2 : noResult(); + } + }; + } + })); + } + + /** + * Performs a sequence of this property with the given property. The returned property holds if + * and only if this property and the given property also hold. If one property does not hold, but + * the other does, then the returned property will produce the same result and the property that + * holds. + * + * @param p The property to sequence this property with. + * @return A sequence of this property with the given property. + */ + public Property sequence(final Property p) { + return fromGen(gen().bind(p.gen(), new F>() { + public F f(final Result res1) { + return new F() { + public Result f(final Result res2) { + return res1.isException() || res1.isProven() || res1.isUnfalsified() ? res1 : res2.isException() || res2.isProven() || res2.isUnfalsified() ? res2 : res1.isFalsified() ? res2 : res2.isFalsified() ? res1 : noResult(); + } + }; + } + })); + } + + /** + * Checks this property using the given arguments and produces a result. + * + * @param r The random generator to use for checking. + * @param minSuccessful The minimum number of successful tests before a result is reached. + * @param maxDiscarded The maximum number of tests discarded because they did not satisfy + * pre-conditions (i.e. {@link #implies(boolean, P1)}). + * @param minSize The minimum size to use for checking. + * @param maxSize The maximum size to use for checking. + * @return A result after checking this property. + */ + @SuppressWarnings({"ThrowableResultOfMethodCallIgnored"}) + public CheckResult check(final Rand r, + final int minSuccessful, + final int maxDiscarded, + final int minSize, + final int maxSize) { + int s = 0; + int d = 0; + float sz = minSize; + CheckResult res; + + while (true) { + final float size = s == 0 && d == 0 ? minSize : sz + (maxSize - sz) / (minSuccessful - s); + try { + final Result x = f.f(round(size)).f(r); + if (x.isNoResult()) + if (d + 1 >= maxDiscarded) { + res = exhausted(s, d + 1); + break; + } else { + sz = size; + d++; + } + else if (x.isProven()) { + res = proven(x.args().some(), s + 1, d); + break; + } else if (x.isUnfalsified()) + if (s + 1 >= minSuccessful) { + res = passed(s + 1, d); + break; + } else { + sz = size; + s++; + } + else if (x.isFalsified()) { + res = falsified(x.args().some(), s, d); + break; + } else if (x.isException()) { + res = propException(x.args().some(), x.exception().some(), s, d); + break; + } + } catch (final Throwable t) { + res = genException(t, s, d); + break; + } + } + + return res; + } + + /** + * Checks this property using a {@link Rand#Rand(F, F) standard random generator} and the given + * arguments to produce a result. + * + * @param minSuccessful The minimum number of successful tests before a result is reached. + * @param maxDiscarded The maximum number of tests discarded because they did not satisfy + * pre-conditions (i.e. {@link #implies(boolean, P1)}). + * @param minSize The minimum size to use for checking. + * @param maxSize The maximum size to use for checking. + * @return A result after checking this property. + */ + public CheckResult check(final int minSuccessful, + final int maxDiscarded, + final int minSize, + final int maxSize) { + return check(Rand.standard, minSuccessful, maxDiscarded, minSize, maxSize); + } + + /** + * Checks this property using the given random generator, 100 minimum successful checks, 500 + * maximum discarded tests, minimum size of 0, maximum size of 100. + * + * @param r The random generator. + * @return A result after checking this property. + */ + public CheckResult check(final Rand r) { + return check(r, 100, 500, 0, 100); + } + + /** + * Checks this property using the given random generator, 100 minimum successful checks, 500 + * maximum discarded tests, the given minimum size and the given maximum size. + * + * @param r The random generator. + * @param minSize The minimum size to use for checking. + * @param maxSize The maximum size to use for checking. + * @return A result after checking this property. + */ + public CheckResult check(final Rand r, final int minSize, final int maxSize) { + return check(r, 100, 500, minSize, maxSize); + } + + /** + * Checks this property using a {@link Rand#Rand(F, F) standard random generator}, 100 minimum + * successful checks, 500 maximum discarded tests and the given arguments to produce a result. + * + * @param minSize The minimum size to use for checking. + * @param maxSize The maximum size to use for checking. + * @return A result after checking this property. + */ + public CheckResult check(final int minSize, + final int maxSize) { + return check(100, 500, minSize, maxSize); + } + + /** + * Checks this property using a {@link Rand#Rand(F, F) standard random generator}, 100 minimum + * successful checks, 500 maximum discarded tests, minimum size of 0, maximum size of 100. + * + * @return A result after checking this property. + */ + public CheckResult check() { + return check(0, 100); + } + + /** + * Checks this property using a {@link Rand#Rand(F, F) standard random generator}, the given minimum + * successful checks, 500 maximum discarded tests, minimum size of 0, maximum size of 100. + * + * @param minSuccessful The minimum number of successful tests before a result is reached. + * @return A result after checking this property. + */ + public CheckResult minSuccessful(final int minSuccessful) { + return check(minSuccessful, 500, 0, 100); + } + + /** + * Checks this property using the given random generator, the given minimum + * successful checks, 500 maximum discarded tests, minimum size of 0, maximum size of 100. + * + * @param r The random generator. + * @param minSuccessful The minimum number of successful tests before a result is reached. + * @return A result after checking this property. + */ + public CheckResult minSuccessful(final Rand r, final int minSuccessful) { + return check(r, minSuccessful, 500, 0, 100); + } + + /** + * Checks this property using a {@link Rand#Rand(F, F) standard random generator}, 100 minimum + * successful checks, the given maximum discarded tests, minimum size of 0, maximum size of 100. + * + * @param maxDiscarded The maximum number of tests discarded because they did not satisfy + * pre-conditions (i.e. {@link #implies(boolean, P1)}). + * @return A result after checking this property. + */ + public CheckResult maxDiscarded(final int maxDiscarded) { + return check(100, maxDiscarded, 0, 100); + } + + /** + * Checks this property using a the given random generator}, 100 minimum + * successful checks, the given maximum discarded tests, minimum size of 0, maximum size of 100. + * + * @param r The random generator. + * @param maxDiscarded The maximum number of tests discarded because they did not satisfy + * pre-conditions (i.e. {@link #implies(boolean, P1)}). + * @return A result after checking this property. + */ + public CheckResult maxDiscarded(final Rand r, final int maxDiscarded) { + return check(r, 100, maxDiscarded, 0, 100); + } + + /** + * Checks this property using a {@link Rand#Rand(F, F) standard random generator}, 100 minimum + * successful checks, 500 maximum discarded tests, the given minimum size, maximum size of 100. + * + * @param minSize The minimum size to use for checking. + * @return A result after checking this property. + */ + public CheckResult minSize(final int minSize) { + return check(100, 500, minSize, 100); + } + + /** + * Checks this property using the given random generator, 100 minimum + * successful checks, 500 maximum discarded tests, the given minimum size, maximum size of 100. + * + * @param r The random generator. + * @param minSize The minimum size to use for checking. + * @return A result after checking this property. + */ + public CheckResult minSize(final Rand r, final int minSize) { + return check(r, 100, 500, minSize, 100); + } + + /** + * Checks this property using a {@link Rand#Rand(F, F) standard random generator}, 100 minimum + * successful checks, 500 maximum discarded tests, minimum size of 0, the given maximum size. + * + * @param maxSize The maximum size to use for checking. + * @return A result after checking this property. + */ + public CheckResult maxSize(final int maxSize) { + return check(100, 500, 0, maxSize); + } + + /** + * Checks this property using the given random generator, 100 minimum + * successful checks, 500 maximum discarded tests, minimum size of 0, the given maximum size. + * + * @param r The random generator. + * @param maxSize The maximum size to use for checking. + * @return A result after checking this property. + */ + public CheckResult maxSize(final Rand r, final int maxSize) { + return check(r, 100, 500, 0, maxSize); + } + + /** + * Returns a property that produces a result only if the given condition satisfies. The result + * will be taken from the given property. + * + * @param b The condition that, if satisfied, produces the given property. + * @param p The property to return if the condition satisfies. + * @return A property that produces a result only if the given condition satisfies. + */ + public static Property implies(final boolean b, final P1 p) { + return b ? p._1() : new Property(new F>() { + public F f(final Integer i) { + return new F() { + public Result f(final Rand r) { + return noResult(); + } + }; + } + }); + } + + /** + * Returns a property from the given function. + * + * @param f The function to construct the returned property with. + * @return A property from the given function. + */ + public static Property prop(final F> f) { + return new Property(f); + } + + /** + * Returns a property that always has the given result. + * + * @param r The result of the returned property. + * @return A property that always has the given result. + */ + public static Property prop(final Result r) { + return new Property(new F>() { + public F f(final Integer integer) { + return new F() { + public Result f(final Rand x) { + return r; + } + }; + } + }); + } + + /** + * Returns a property that is either proven (the given condition satsifies) or falsified + * otherwise. + * + * @param b The condition that, if satisfied, returns a property that is proven; otherwise, the + * property is falsified. + * @return A property that is either proven (the given condition satsifies) or falsified + * otherwise. + */ + public static Property prop(final boolean b) { + return b ? prop(Result.proven(List.>nil())) : prop(Result.falsified(List.>nil())); + } + + /** + * Constructs a property from a generator of results. + * + * @param g The generator of results to constructor a property with. + * @return A property from a generator of results. + */ + public static Property fromGen(final Gen g) { + return prop(new F>() { + public F f(final Integer i) { + return new F() { + public Result f(final Rand r) { + return g.gen(i, r); + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param g The generator to produces values from to produce the property with. + * @param shrink The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property forall(final Gen g, final Shrink shrink, final F> f) { + return prop(new F>() { + public F f(final Integer i) { + return new F() { + public Result f(final Rand r) { + final class Util { + @SuppressWarnings({"IfMayBeConditional"}) + Option> first(final Stream as, final int shrinks) { + final Stream>> results = as.map(new F>>() { + public Option> f(final A a) { + final Result result = exception(f.f(a)).prop(i, r); + + return result.toOption().map(new F>() { + public P2 f(final Result result) { + return p(a, result.provenAsUnfalsified().addArg(arg(a, shrinks))); + } + }); + } + }); + + if (results.isEmpty()) + return none(); + else return results.find(new F>, Boolean>() { + public Boolean f(final Option> o) { + return failed(o); + } + }).orSome(new P1>>() { + public Option> _1() { + return results.head(); + } + }); + } + + public boolean failed(final Option> o) { + return o.isSome() && o.some()._2().failed(); + } + } + + final Util u = new Util(); + + Option> x = u.first(Stream.single(g.gen(i, r)), 0); + final F, Result> __2 = __2(); + if (u.failed(x)) { + Option or; + int shrinks = 0; + + do { + shrinks++; + or = x.map(__2); + x = u.first(shrink.shrink(x.some()._1()), shrinks); + } + while (u.failed(x)); + + return noResult(or); + } else + return noResult(x.map(__2)); + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property propertyP(final Arbitrary aa, final Shrink sa, final F> f) { + return forall(aa.gen, sa, f); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, final Shrink sa, final F f) { + return propertyP(aa, sa, P1.curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property propertyP(final Arbitrary aa, final F> f) { + return propertyP(aa, Shrink.empty(), f); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, final F f) { + return propertyP(aa, P1.curry(f)); + } + + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property propertyP(final Arbitrary aa, final Arbitrary ab, final Shrink sa, final Shrink sb, final F>> f) { + return property(aa, sa, new F() { + public Property f(final A a) { + return propertyP(ab, sb, new F>() { + public P1 f(final B b) { + return f.f(a).f(b); + } + }); + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, final Arbitrary ab, final Shrink sa, final Shrink sb, final F> f) { + return propertyP(aa, ab, sa, sb, compose2(P.p1(), f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property propertyP(final Arbitrary aa, final Arbitrary ab, final F>> f) { + return property(aa, new F() { + public Property f(final A a) { + return propertyP(ab, new F>() { + public P1 f(final B b) { + return f.f(a).f(b); + } + }); + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, final Arbitrary ab, final F> f) { + return propertyP(aa, ab, compose2(P.p1(), f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property propertyP(final Arbitrary aa, final Arbitrary ab, final Shrink sa, final Shrink sb, final F2> f) { + return propertyP(aa, ab, sa, sb, curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, final Arbitrary ab, final Shrink sa, final Shrink sb, final F2 f) { + return propertyP(aa, ab, sa, sb, compose2(P.p1(), curry(f))); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property propertyP(final Arbitrary aa, final Arbitrary ab, final F2> f) { + return propertyP(aa, ab, curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, final Arbitrary ab, final F2 f) { + return propertyP(aa, ab, compose2(P.p1(), curry(f))); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param sc The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Shrink sa, + final Shrink sb, + final Shrink sc, + final F>> f) { + return property(aa, ab, sa, sb, new F>() { + public F f(final A a) { + return new F() { + public Property f(final B b) { + return property(ac, sc, new F() { + public Property f(final C c) { + return f.f(a).f(b).f(c); + } + }); + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final F>> f) { + return property(aa, ab, new F>() { + public F f(final A a) { + return new F() { + public Property f(final B b) { + return property(ac, new F() { + public Property f(final C c) { + return f.f(a).f(b).f(c); + } + }); + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param sc The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Shrink sa, + final Shrink sb, + final Shrink sc, + final F3 f) { + return property(aa, ab, ac, sa, sb, sc, curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final F3 f) { + return property(aa, ab, ac, curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param sc The shrink strategy to use upon falsification. + * @param sd The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Shrink sa, + final Shrink sb, + final Shrink sc, + final Shrink sd, + final F>>> f) { + return property(aa, ab, ac, sa, sb, sc, new F>>() { + public F> f(final A a) { + return new F>() { + public F f(final B b) { + return new F() { + public Property f(final C c) { + return property(ad, sd, new F() { + public Property f(final D d) { + return f.f(a).f(b).f(c).f(d); + } + }); + } + }; + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final F>>> f) { + return property(aa, ab, ac, new F>>() { + public F> f(final A a) { + return new F>() { + public F f(final B b) { + return new F() { + public Property f(final C c) { + return property(ad, new F() { + public Property f(final D d) { + return f.f(a).f(b).f(c).f(d); + } + }); + } + }; + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param sc The shrink strategy to use upon falsification. + * @param sd The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Shrink sa, + final Shrink sb, + final Shrink sc, + final Shrink sd, + final F4 f) { + return property(aa, ab, ac, ad, sa, sb, sc, sd, curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final F4 f) { + return property(aa, ab, ac, ad, curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param sc The shrink strategy to use upon falsification. + * @param sd The shrink strategy to use upon falsification. + * @param se The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Shrink sa, + final Shrink sb, + final Shrink sc, + final Shrink sd, + final Shrink se, + final F>>>> f) { + return property(aa, ab, ac, ad, sa, sb, sc, sd, new F>>>() { + public F>> f(final A a) { + return new F>>() { + public F> f(final B b) { + return new F>() { + public F f(final C c) { + return new F() { + public Property f(final D d) { + return property(ae, se, new F() { + public Property f(final E e) { + return f.f(a).f(b).f(c).f(d).f(e); + } + }); + } + }; + } + }; + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final F>>>> f) { + return property(aa, ab, ac, ad, new F>>>() { + public F>> f(final A a) { + return new F>>() { + public F> f(final B b) { + return new F>() { + public F f(final C c) { + return new F() { + public Property f(final D d) { + return property(ae, new F() { + public Property f(final E e) { + return f.f(a).f(b).f(c).f(d).f(e); + } + }); + } + }; + } + }; + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param sc The shrink strategy to use upon falsification. + * @param sd The shrink strategy to use upon falsification. + * @param se The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Shrink sa, + final Shrink sb, + final Shrink sc, + final Shrink sd, + final Shrink se, + final F5 f) { + return property(aa, ab, ac, ad, ae, sa, sb, sc, sd, se, curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final F5 f) { + return property(aa, ab, ac, ad, ae, curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param af The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param sc The shrink strategy to use upon falsification. + * @param sd The shrink strategy to use upon falsification. + * @param se The shrink strategy to use upon falsification. + * @param sf The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Shrink sa, + final Shrink sb, + final Shrink sc, + final Shrink sd, + final Shrink se, + final Shrink sf, + final F>>>>> f) { + return property(aa, ab, ac, ad, ae, sa, sb, sc, sd, se, new F>>>>() { + public F>>> f(final A a) { + return new F>>>() { + public F>> f(final B b) { + return new F>>() { + public F> f(final C c) { + return new F>() { + public F f(final D d) { + return new F() { + public Property f(final E e) { + return property(af, sf, new F() { + public Property f(final F$ f$) { + return f.f(a).f(b).f(c).f(d).f(e).f(f$); + } + }); + } + }; + } + }; + } + }; + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param af The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final F>>>>> f) { + return property(aa, ab, ac, ad, ae, new F>>>>() { + public F>>> f(final A a) { + return new F>>>() { + public F>> f(final B b) { + return new F>>() { + public F> f(final C c) { + return new F>() { + public F f(final D d) { + return new F() { + public Property f(final E e) { + return property(af, new F() { + public Property f(final F$ f$) { + return f.f(a).f(b).f(c).f(d).f(e).f(f$); + } + }); + } + }; + } + }; + } + }; + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param af The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param sc The shrink strategy to use upon falsification. + * @param sd The shrink strategy to use upon falsification. + * @param se The shrink strategy to use upon falsification. + * @param sf The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Shrink sa, + final Shrink sb, + final Shrink sc, + final Shrink sd, + final Shrink se, + final Shrink sf, + final F6 f) { + return property(aa, ab, ac, ad, ae, af, sa, sb, sc, sd, se, sf, curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param af The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final F6 f) { + return property(aa, ab, ac, ad, ae, af, curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param af The arbitrrary to produces values from to produce the property with. + * @param ag The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param sc The shrink strategy to use upon falsification. + * @param sd The shrink strategy to use upon falsification. + * @param se The shrink strategy to use upon falsification. + * @param sf The shrink strategy to use upon falsification. + * @param sg The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Arbitrary ag, + final Shrink sa, + final Shrink sb, + final Shrink sc, + final Shrink sd, + final Shrink se, + final Shrink sf, + final Shrink sg, + final F>>>>>> f) { + return property(aa, ab, ac, ad, ae, af, sa, sb, sc, sd, se, sf, new F>>>>>() { + public F>>>> f(final A a) { + return new F>>>>() { + public F>>> f(final B b) { + return new F>>>() { + public F>> f(final C c) { + return new F>>() { + public F> f(final D d) { + return new F>() { + public F f(final E e) { + return new F() { + public Property f(final F$ f$) { + return property(ag, sg, new F() { + public Property f(final G g) { + return f.f(a).f(b).f(c).f(d).f(e).f(f$).f(g); + } + }); + } + }; + } + }; + } + }; + } + }; + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param af The arbitrrary to produces values from to produce the property with. + * @param ag The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Arbitrary ag, + final F>>>>>> f) { + return property(aa, ab, ac, ad, ae, af, new F>>>>>() { + public F>>>> f(final A a) { + return new F>>>>() { + public F>>> f(final B b) { + return new F>>>() { + public F>> f(final C c) { + return new F>>() { + public F> f(final D d) { + return new F>() { + public F f(final E e) { + return new F() { + public Property f(final F$ f$) { + return property(ag, new F() { + public Property f(final G g) { + return f.f(a).f(b).f(c).f(d).f(e).f(f$).f(g); + } + }); + } + }; + } + }; + } + }; + } + }; + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param af The arbitrrary to produces values from to produce the property with. + * @param ag The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param sc The shrink strategy to use upon falsification. + * @param sd The shrink strategy to use upon falsification. + * @param se The shrink strategy to use upon falsification. + * @param sf The shrink strategy to use upon falsification. + * @param sg The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Arbitrary ag, + final Shrink sa, + final Shrink sb, + final Shrink sc, + final Shrink sd, + final Shrink se, + final Shrink sf, + final Shrink sg, + final F7 f) { + return property(aa, ab, ac, ad, ae, af, ag, sa, sb, sc, sd, se, sf, sg, curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param af The arbitrrary to produces values from to produce the property with. + * @param ag The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Arbitrary ag, + final F7 f) { + return property(aa, ab, ac, ad, ae, af, ag, curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param af The arbitrrary to produces values from to produce the property with. + * @param ag The arbitrrary to produces values from to produce the property with. + * @param ah The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param sc The shrink strategy to use upon falsification. + * @param sd The shrink strategy to use upon falsification. + * @param se The shrink strategy to use upon falsification. + * @param sf The shrink strategy to use upon falsification. + * @param sg The shrink strategy to use upon falsification. + * @param sh The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Arbitrary ag, + final Arbitrary ah, + final Shrink sa, + final Shrink sb, + final Shrink sc, + final Shrink sd, + final Shrink se, + final Shrink sf, + final Shrink sg, + final Shrink sh, + final F>>>>>>> f) { + return property(aa, ab, ac, ad, ae, af, ag, sa, sb, sc, sd, se, sf, sg, new F>>>>>>() { + public F>>>>> f(final A a) { + return new F>>>>>() { + public F>>>> f(final B b) { + return new F>>>>() { + public F>>> f(final C c) { + return new F>>>() { + public F>> f(final D d) { + return new F>>() { + public F> f(final E e) { + return new F>() { + public F f(final F$ f$) { + return new F() { + public Property f(final G g) { + return property(ah, sh, new F() { + public Property f(final H h) { + return f.f(a).f(b).f(c).f(d).f(e).f(f$).f(g).f(h); + } + }); + } + }; + } + }; + } + }; + } + }; + } + }; + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param af The arbitrrary to produces values from to produce the property with. + * @param ag The arbitrrary to produces values from to produce the property with. + * @param ah The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Arbitrary ag, + final Arbitrary ah, + final F>>>>>>> f) { + return property(aa, ab, ac, ad, ae, af, ag, new F>>>>>>() { + public F>>>>> f(final A a) { + return new F>>>>>() { + public F>>>> f(final B b) { + return new F>>>>() { + public F>>> f(final C c) { + return new F>>>() { + public F>> f(final D d) { + return new F>>() { + public F> f(final E e) { + return new F>() { + public F f(final F$ f$) { + return new F() { + public Property f(final G g) { + return property(ah, new F() { + public Property f(final H h) { + return f.f(a).f(b).f(c).f(d).f(e).f(f$).f(g).f(h); + } + }); + } + }; + } + }; + } + }; + } + }; + } + }; + } + }; + } + }); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param af The arbitrrary to produces values from to produce the property with. + * @param ag The arbitrrary to produces values from to produce the property with. + * @param ah The arbitrrary to produces values from to produce the property with. + * @param sa The shrink strategy to use upon falsification. + * @param sb The shrink strategy to use upon falsification. + * @param sc The shrink strategy to use upon falsification. + * @param sd The shrink strategy to use upon falsification. + * @param se The shrink strategy to use upon falsification. + * @param sf The shrink strategy to use upon falsification. + * @param sg The shrink strategy to use upon falsification. + * @param sh The shrink strategy to use upon falsification. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Arbitrary ag, + final Arbitrary ah, + final Shrink sa, + final Shrink sb, + final Shrink sc, + final Shrink sd, + final Shrink se, + final Shrink sf, + final Shrink sg, + final Shrink sh, + final F8 f) { + return property(aa, ab, ac, ad, ae, af, ag, ah, sa, sb, sc, sd, se, sf, sg, sh, curry(f)); + } + + /** + * Returns a property where its result is derived from universal quantification across the + * application of its arguments. No shrinking occurs upon falsification. + * + * @param aa The arbitrrary to produces values from to produce the property with. + * @param ab The arbitrrary to produces values from to produce the property with. + * @param ac The arbitrrary to produces values from to produce the property with. + * @param ad The arbitrrary to produces values from to produce the property with. + * @param ae The arbitrrary to produces values from to produce the property with. + * @param af The arbitrrary to produces values from to produce the property with. + * @param ag The arbitrrary to produces values from to produce the property with. + * @param ah The arbitrrary to produces values from to produce the property with. + * @param f The function to produce properties with results. + * @return A property where its result is derived from universal quantification across the + * application of its arguments. + */ + public static Property property(final Arbitrary aa, + final Arbitrary ab, + final Arbitrary ac, + final Arbitrary ad, + final Arbitrary ae, + final Arbitrary af, + final Arbitrary ag, + final Arbitrary ah, + final F8 f) { + return property(aa, ab, ac, ad, ae, af, ag, ah, curry(f)); + } + + /** + * Returns a property that has a result of exception, if the evaluation of the given property + * throws an exception; otherwise, the given property is returned. + * + * @param p A property to evaluate to check for an exception. + * @return A property that has a result of exception, if the evaluation of the given property + * throws an exception; otherwise, the given property is returned. + */ + public static Property exception(final P1 p) { + try { + return p._1(); + } catch (final Throwable t) { + return new Property(new F>() { + public F f(final Integer i) { + return new F() { + public Result f(final Rand r) { + return Result.exception(List.>nil(), t); + } + }; + } + }); + } + } + + + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/Rand.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/Rand.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,156 @@ +package fj.test; + +import fj.F; +import fj.data.Option; +import static fj.data.Option.some; + +import static java.lang.Math.max; +import static java.lang.Math.min; +import java.util.Random; + +/** + * A random number generator. + * + * @version %build.number% + */ +public final class Rand { + private final F, F>> f; + private final F, F>> g; + + private Rand(final F, F>> f, final F, F>> g) { + this.f = f; + this.g = g; + } + + /** + * Randomly chooses a value between the given range (inclusive). + * + * @param seed The seed to use for random generation. + * @param from The minimum value to choose. + * @param to The maximum value to choose. + * @return A random value in the given range. + */ + public int choose(final long seed, final int from, final int to) { + return f.f(some(seed)).f(from).f(to); + } + + /** + * Randomly chooses a value between the given range (inclusive). + * + * @param from The minimum value to choose. + * @param to The maximum value to choose. + * @return A random value in the given range. + */ + public int choose(final int from, final int to) { + return f.f(Option.none()).f(from).f(to); + } + + /** + * Randomly chooses a value between the given range (inclusive). + * + * @param seed The seed to use for random generation. + * @param from The minimum value to choose. + * @param to The maximum value to choose. + * @return A random value in the given range. + */ + public double choose(final long seed, final double from, final double to) { + return g.f(some(seed)).f(from).f(to); + } + + /** + * Randomly chooses a value between the given range (inclusive). + * + * @param from The minimum value to choose. + * @param to The maximum value to choose. + * @return A random value in the given range. + */ + public double choose(final double from, final double to) { + return g.f(Option.none()).f(from).f(to); + } + + /** + * Gives this random generator a new seed. + * + * @param seed The seed of the new random generator. + * @return A random generator with the given seed. + */ + public Rand reseed(final long seed) { + return new Rand(new F, F>>() { + public F> f(final Option old) { + return new F>() { + public F f(final Integer from) { + return new F() { + public Integer f(final Integer to) { + return f.f(some(seed)).f(from).f(to); + } + }; + } + }; + } + }, new F, F>>() { + public F> f(final Option old) { + return new F>() { + public F f(final Double from) { + return new F() { + public Double f(final Double to) { + return g.f(some(seed)).f(from).f(to); + } + }; + } + }; + } + }); + } + + /** + * Constructs a random generator from the given functions that supply a range to produce a + * result. + * + * @param f The integer random generator. + * @param g The floating-point random generator. + * @return A random generator from the given functions that supply a range to produce a result. + */ + public static Rand rand(final F, F>> f, final F, F>> g) { + return new Rand(f, g); + } + + + private static final F fr = new F() { + public Random f(final Long x) { + return new Random(x); + } + }; + + /** + * A standard random generator that uses {@link Random}. + */ + public static final Rand standard = new Rand(new F, F>>() { + public F> f(final Option seed) { + return new F>() { + public F f(final Integer from) { + return new F() { + public Integer f(final Integer to) { + final int f = min(from, to); + final int t = max(from, to); + return f + seed.map(fr).orSome(new Random()).nextInt(t - f + 1); + } + }; + } + }; + } + }, new F, F>>() { + public F> f(final Option seed) { + return new F>() { + public F f(final Double from) { + return new F() { + public Double f(final Double to) { + final double f = min(from, to); + final double t = max(from, to); + return seed.map(fr).orSome(new Random()).nextDouble() * (t - f) + f; + } + }; + } + }; + } + }); +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/Result.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/Result.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,216 @@ +package fj.test; + +import fj.F; +import fj.P1; +import fj.data.List; +import fj.data.Option; +import static fj.data.Option.none; +import static fj.data.Option.some; + +/** + * The result of evaluating a property. + * + * @version %build.number% + */ +public final class Result { + private final Option>> args; + private final R r; + private final Option t; + + private enum R { + Unfalsified, Falsified, Proven, Exception, NoResult + } + + private Result(final Option>> args, final R r, final Option t) { + this.args = args; + this.r = r; + this.t = t; + } + + /** + * Returns the potential arguments associated with this result. This will only have a value, if + * and only if {@link #noResult(Option) !noResult()} holds. + * + * @return The potential arguments associated with this result. + */ + public Option>> args() { + return args; + } + + /** + * Returns the potential exception associated with this result. This will only have a value if and + * only if this result is an exception result. + * + * @return The potential exception associated with this result. + */ + public Option exception() { + return t; + } + + /** + * Returns true if this result is unfalsified; otherwise, false. + * + * @return true if this result is unfalsified; otherwise, false. + */ + public boolean isUnfalsified() { + return r == R.Unfalsified; + } + + /** + * Returns true if this result is falsified; otherwise, false. + * + * @return true if this result is falsified; otherwise, false. + */ + public boolean isFalsified() { + return r == R.Falsified; + } + + /** + * Returns true if this result is proven; otherwise, false. + * + * @return true if this result is proven; otherwise, false. + */ + public boolean isProven() { + return r == R.Proven; + } + + /** + * Returns true if this result is an exception; otherwise, false. + * + * @return true if this result is an exception; otherwise, false. + */ + public boolean isException() { + return r == R.Exception; + } + + /** + * Returns true if this result is no result; otherwise, false. + * + * @return true if this result is no result; otherwise, false. + */ + public boolean isNoResult() { + return r == R.NoResult; + } + + /** + * Returns true if this result is falsified or an exception; otherwise, + * false. + * + * @return true if this result is falsified or an exception; otherwise, + * false. + */ + public boolean failed() { + return isFalsified() || isException(); + } + + /** + * Returns true if this result is unfalsified or proven; otherwise, + * false. + * + * @return true if this result is unfalsified or proven; otherwise, + * false. + */ + public boolean passed() { + return isUnfalsified() || isProven(); + } + + /** + * If this result is proven, alter it to be unfalsified with the same arguments; otherwise, return + * this. + * + * @return If this result is proven, alter it to be unfalsified with the same arguments; + * otherwise, return this. + */ + public Result provenAsUnfalsified() { + return isProven() ? unfalsified(args.some()) : this; + } + + /** + * Adds an argument to this result. + * + * @param a The argument to add. + * @return A result with the new argument. + */ + public Result addArg(final Arg a) { + final F, F>, List>>> cons = List.cons(); + return new Result(args.map(cons.f(a)), r, t); + } + + /** + * Returns a potential result for this result. This will have a value if this result is + * {@link #noResult(Option) !noResult()}. + * + * @return A potential result for this result. + */ + @SuppressWarnings({"IfMayBeConditional"}) + public Option toOption() { + if(isNoResult()) + return none(); + else + return some(this); + } + + /** + * Returns a result from the given potential result. + * + * @param r The potential result. + * @return The result that may be {@link #noResult() noResult()}. + */ + public static Result noResult(final Option r) { + return r.orSome(new P1() { + public Result _1() { + return noResult(); + } + }); + } + + /** + * Returns a result representing no result. + * + * @return A result representing no result. + */ + public static Result noResult() { + return new Result(Option.>>none(), R.NoResult, Option.none()); + } + + /** + * Returns an unfalsified result. + * + * @param args The arguments used during the failure of falsification. + * @return An unfalsified result. + */ + public static Result unfalsified(final List> args) { + return new Result(some(args), R.Unfalsified, Option.none()); + } + + /** + * Returns a falsified result. + * + * @param args The arguments used during falsification. + * @return A falsified result. + */ + public static Result falsified(final List> args) { + return new Result(some(args), R.Falsified, Option.none()); + } + + /** + * Returns a proven result. + * + * @param args The arguments used during proof. + * @return A proven result. + */ + public static Result proven(final List> args) { + return new Result(some(args), R.Proven, Option.none()); + } + + /** + * Returns an exception result. + * + * @param args The arguments used when the exception occurred. + * @param t The exception that occurred. + * @return A exception result. + */ + public static Result exception(final List> args, final Throwable t) { + return new Result(some(args), R.Exception, some(t)); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/Shrink.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/Shrink.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,1081 @@ +package fj.test; + +import fj.F; +import static fj.P.p; +import static fj.P.p2; +import static fj.P.p3; +import static fj.P.p4; +import static fj.P.p5; +import static fj.P.p6; +import static fj.P.p7; +import static fj.P.p8; + +import fj.Function; +import fj.P1; +import fj.P2; +import fj.P3; +import fj.P4; +import fj.P5; +import fj.P6; +import fj.P7; +import fj.P8; +import static fj.Primitive.Byte_Long; +import static fj.Primitive.Character_Long; +import static fj.Primitive.Double_Long; +import static fj.Primitive.Float_Long; +import static fj.Primitive.Integer_Long; +import static fj.Primitive.Long_Byte; +import static fj.Primitive.Long_Character; +import static fj.Primitive.Long_Double; +import static fj.Primitive.Long_Float; +import static fj.Primitive.Long_Integer; +import static fj.Primitive.Long_Short; +import static fj.Primitive.Short_Long; +import static fj.data.Array.array; +import fj.data.Conversions; +import static fj.data.List.isNotEmpty_; +import fj.data.Array; +import fj.data.Either; +import fj.data.Java; +import fj.data.List; +import fj.data.Option; +import fj.data.Stream; + +import static fj.data.Stream.cons; +import static fj.data.Stream.iterate; +import static fj.data.Stream.nil; + +import static java.lang.System.arraycopy; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Calendar; +import java.util.Date; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.PriorityQueue; +import java.util.Properties; +import java.util.Stack; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.Vector; +import java.util.WeakHashMap; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Delayed; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.SynchronousQueue; + +/** + * Represents a shrinking strategy over the given type parameter if that type can be represented as + * a tree structure. This is used in falsification to produce the smallest counter-example, rather + * than the first counter-example. + * + * @version %build.number% + */ +public final class Shrink { + private final F> f; + + private Shrink(final F> f) { + this.f = f; + } + + /** + * Returns a shrink of the given argument. + * + * @param a The argument to shrink. + * @return A shrink of the given argument. + */ + public Stream shrink(final A a) { + return f.f(a); + } + + /** + * Creates a shrink from this shrink and the given symmetric transformations. + * + * @param f A transformation from this shrink type to the new shrink type. + * @param g A transformation from the new shrink type to this shrink type. + * @return A shrink from this shrink and the given symmetric transformations. + */ + public Shrink map(final F f, final F g) { + return new Shrink(new F>() { + public Stream f(final B b) { + return Shrink.this.f.f(g.f(b)).map(f); + } + }); + } + + + /** + * Constructs a shrink strategy from the given function that produces a tree of values given a + * value. + * + * @param f A function that produces a tree of values given a value. + * @return A shrink strategy from the given function that produces a tree of values given a + * value. + */ + public static Shrink shrink(final F> f) { + return new Shrink(f); + } + + /** + * Returns a shrink strategy that cannot be reduced further. + * + * @return A shrink strategy that cannot be reduced further. + */ + public static Shrink empty() { + return new Shrink(new F>() { + public Stream f(final A a) { + return nil(); + } + }); + } + + /** + * A shrink strategy for longs using 0 as the bottom of the shrink. + */ + public static final Shrink shrinkLong = new Shrink(new F>() { + public Stream f(final Long i) { + if (i == 0L) + return nil(); + else { + final Stream is = cons(0L, new P1>() { + public Stream _1() { + return iterate(new F() { + public Long f(final Long x) { + return x / 2L; + } + }, i).takeWhile(new F() { + public Boolean f(final Long x) { + return x != 0L; + } + }).map(new F() { + public Long f(final Long x) { + return i - x; + } + }); + } + }); + + return i < 0L ? cons(-i, new P1>() { + public Stream _1() { + return is; + } + }) : is; + } + } + }); + + /** + * A shrink strategy for booleans using false as the bottom of the shrink. + */ + public static final Shrink shrinkBoolean = + shrink(Function.>constant(Stream.single(false))); + + /** + * A shrink strategy for integers using 0 as the bottom of the shrink. + */ + public static final Shrink shrinkInteger = shrinkLong.map(Long_Integer, Integer_Long); + + /** + * A shrink strategy for bytes using 0 as the bottom of the shrink. + */ + public static final Shrink shrinkByte = shrinkLong.map(Long_Byte, Byte_Long); + + /** + * A shrink strategy for characters using 0 as the bottom of the shrink. + */ + public static final Shrink shrinkCharacter = shrinkLong.map(Long_Character, Character_Long); + + /** + * A shrink strategy for shorts using 0 as the bottom of the shrink. + */ + public static final Shrink shrinkShort = shrinkLong.map(Long_Short, Short_Long); + + /** + * A shrink strategy for floats using 0 as the bottom of the shrink. + */ + public static final Shrink shrinkFloat = shrinkLong.map(Long_Float, Float_Long); + + /** + * A shrink strategy for doubles using 0 as the bottom of the shrink. + */ + public static final Shrink shrinkDouble = shrinkLong.map(Long_Double, Double_Long); + + /** + * Returns a shrink strategy for optional values. A 'no value' is already fully + * shrunk, otherwise, the shrinking occurs on the value with the given shrink strategy. + * + * @param sa The shrink strategy for the potential value. + * @return A shrink strategy for optional values. + */ + public static Shrink> shrinkOption(final Shrink sa) { + return new Shrink>(new F, Stream>>() { + public Stream> f(final Option o) { + return o.isNone() ? + Stream.>nil() : + cons(Option.none(), new P1>>() { + public Stream> _1() { + return sa.shrink(o.some()).map(Option.some_()); + } + }); + } + }); + } + + /** + * Returns a shrink strategy for either values. + * + * @param sa The shrinking strategy for left values. + * @param sb The shrinking strategy for right values. + * @return A shrink strategy for either values. + */ + public static Shrink> shrinkEither(final Shrink sa, final Shrink sb) { + return new Shrink>(new F, Stream>>() { + public Stream> f(final Either e) { + return e.isLeft() ? + sa.shrink(e.left().value()).map(Either.left_()) : + sb.shrink(e.right().value()).map(Either.right_()); + } + }); + } + + /** + * Returns a shrink strategy for lists. An empty list is fully shrunk. + * + * @param sa The shrink strategy for the elements of the list. + * @return A shrink strategy for lists. + */ + public static Shrink> shrinkList(final Shrink sa) { + final class Util { + Stream> removeChunks(final int n, final List as) { + if (as.isEmpty()) + return nil(); + else if (as.tail().isEmpty()) + return cons(List.nil(), Stream.>nil_()); + else { + final int n1 = n / 2; + final int n2 = n - n1; + + final List as1 = as.take(n1); + final F, Boolean> isNotEmpty = isNotEmpty_(); + return cons(as1, new P1>>() { + public Stream> _1() { + final List as2 = as.drop(n1); + return cons(as2, new P1>>() { + public Stream> _1() { + return removeChunks(n1, as1).filter(isNotEmpty).map(new F, List>() { + public List f(final List aas) { + return aas.append(as2); + } + }).interleave(removeChunks(n2, as2).filter(isNotEmpty).map(new F, List>() { + public List f(final List aas) { + return as1.append(aas); + } + })); + } + }); + } + }); + } + } + + @SuppressWarnings({"IfMayBeConditional"}) + Stream> shrinkOne(final List as) { + if (as.isEmpty()) + return nil(); + else + return sa.shrink(as.head()).map(new F>() { + public List f(final A a) { + return as.tail().cons(a); + } + }).append(shrinkOne(as.tail()).map(new F, List>() { + public List f(final List aas) { + return aas.cons(as.head()); + } + })); + } + } + + return new Shrink>(new F, Stream>>() { + public Stream> f(final List as) { + final Util u = new Util(); + return u.removeChunks(as.length(), as).append(u.shrinkOne(as)); + } + }); + } + + /** + * Returns a shrink strategy for arrays. An empty array is fully shrunk. + * + * @param sa The shrink strategy for the elements of the array. + * @return A shrink strategy for arrays. + */ + public static Shrink> shrinkArray(final Shrink sa) { + return shrinkList(sa).map(Conversions.List_Array(), Conversions.Array_List()); + } + + /** + * Returns a shrink strategy for streams. An empty stream is fully shrunk. + * + * @param sa The shrink strategy for the elements of the stream. + * @return A shrink strategy for streams. + */ + public static Shrink> shrinkStream(final Shrink sa) { + return shrinkList(sa).map(Conversions.List_Stream(), Conversions.Stream_List()); + } + + /** + * A shrink strategy for strings using the empty string as the bottom of the shrink. + */ + public static final Shrink shrinkString = + shrinkList(shrinkCharacter).map(Conversions.List_String, Conversions.String_List); + + /** + * A shrink strategy for string buffers using the empty string as the bottom of the shrink. + */ + public static final Shrink shrinkStringBuffer = + shrinkList(shrinkCharacter).map(Conversions.List_StringBuffer, Conversions.StringBuffer_List); + + /** + * A shrink strategy for string builders using the empty string as the bottom of the shrink. + */ + public static final Shrink shrinkStringBuilder = + shrinkList(shrinkCharacter).map(Conversions.List_StringBuilder, Conversions.StringBuilder_List); + + /** + * A shrink strategy for throwables. + * + * @param ss A shrink strategy for throwable messages. + * @return A shrink strategy for throwables. + */ + public static Shrink shrinkThrowable(final Shrink ss) { + return ss.map(new F() { + public Throwable f(final String s) { + return new Throwable(s); + } + }, new F() { + public String f(final Throwable t) { + return t.getMessage(); + } + }); + } + + /** + * A shrink strategy for throwables. + */ + public static final Shrink shrinkThrowable = shrinkThrowable(shrinkString); + + // BEGIN java.util + + /** + * Returns a shrink strategy for array lists. An empty array list is fully shrunk. + * + * @param sa The shrink strategy for the elements of the array list. + * @return A shrink strategy for array lists. + */ + public static Shrink> shrinkArrayList(final Shrink sa) { + return shrinkList(sa).map(Java.List_ArrayList(), Java.ArrayList_List()); + } + + /** + * A shrink strategy for bit sets. + */ + public static final Shrink shrinkBitSet = + shrinkList(shrinkBoolean).map(Java.List_BitSet, Java.BitSet_List); + + /** + * A shrink strategy for calendars. + */ + public static final Shrink shrinkCalendar = + shrinkLong.map(new F() { + public Calendar f(final Long i) { + final Calendar c = Calendar.getInstance(); + c.setTimeInMillis(i); + return c; + } + }, new F() { + public Long f(final Calendar c) { + return c.getTime().getTime(); + } + }); + + /** + * A shrink strategy for dates. + */ + public static final Shrink shrinkDate = + shrinkLong.map(new F() { + public Date f(final Long i) { + return new Date(i); + } + }, new F() { + public Long f(final Date d) { + return d.getTime(); + } + }); + + /** + * A shrink strategy for enum maps. + * + * @param sk The shrink strategy for keys. + * @param sv The shrink stratgey for values. + * @return A shrink strategy for enum maps. + */ + public static , V> Shrink> shrinkEnumMap(final Shrink sk, final Shrink sv) { + return shrinkHashtable(sk, sv).map(new F, EnumMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public EnumMap f(final Hashtable h) { + return new EnumMap(h); + } + }, new F, Hashtable>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Hashtable f(final EnumMap m) { + return new Hashtable(m); + } + }); + } + + /** + * A shrink strategy for enum sets. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for enum sets. + */ + public static > Shrink> shrinkEnumSet(final Shrink sa) { + return shrinkList(sa).map(Java.List_EnumSet(), Java.EnumSet_List()); + } + + /** + * A shrink strategy for gregorian calendars. + */ + public static final Shrink shrinkGregorianCalendar = + shrinkLong.map(new F() { + public GregorianCalendar f(final Long i) { + final GregorianCalendar c = new GregorianCalendar(); + c.setTimeInMillis(i); + return c; + } + }, new F() { + public Long f(final GregorianCalendar c) { + return c.getTime().getTime(); + } + }); + + /** + * A shrink strategy for hash maps. + * + * @param sk The shrink strategy for keys. + * @param sv The shrink stratgey for values. + * @return A shrink strategy for hash maps. + */ + public static Shrink> shrinkHashMap(final Shrink sk, final Shrink sv) { + return shrinkHashtable(sk, sv).map(new F, HashMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public HashMap f(final Hashtable h) { + return new HashMap(h); + } + }, new F, Hashtable>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Hashtable f(final HashMap m) { + return new Hashtable(m); + } + }); + } + + /** + * A shrink strategy for hash sets. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for hash sets. + */ + public static Shrink> shrinkHashSet(final Shrink sa) { + return shrinkList(sa).map(Java.List_HashSet(), Java.HashSet_List()); + } + + /** + * A shrink strategy for hash tables. + * + * @param sk The shrink strategy for keys. + * @param sv The shrink stratgey for values. + * @return A shrink strategy for hash tables. + */ + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public static Shrink> shrinkHashtable(final Shrink sk, final Shrink sv) { + return shrinkList(shrinkP2(sk, sv)).map(new F>, Hashtable>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Hashtable f(final List> kvs) { + final Hashtable h = new Hashtable(); + kvs.foreachDoEffect(kv -> h.put(kv._1(), kv._2())); + return h; + } + }, new F, List>>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public List> f(final Hashtable h) { + List> x = List.nil(); + + for (final K k : h.keySet()) { + x = x.snoc(p(k, h.get(k))); + } + + return x; + } + }); + } + + /** + * A shrink strategy for identity hash maps. + * + * @param sk The shrink strategy for keys. + * @param sv The shrink stratgey for values. + * @return A shrink strategy for identity hash maps. + */ + public static Shrink> shrinkIdentityHashMap(final Shrink sk, final Shrink sv) { + return shrinkHashtable(sk, sv).map(new F, IdentityHashMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public IdentityHashMap f(final Hashtable h) { + return new IdentityHashMap(h); + } + }, new F, Hashtable>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Hashtable f(final IdentityHashMap m) { + return new Hashtable(m); + } + }); + } + + /** + * A shrink strategy for linked hash maps. + * + * @param sk The shrink strategy for keys. + * @param sv The shrink stratgey for values. + * @return A shrink strategy for linked hash maps. + */ + public static Shrink> shrinkLinkedHashMap(final Shrink sk, final Shrink sv) { + return shrinkHashtable(sk, sv).map(new F, LinkedHashMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public LinkedHashMap f(final Hashtable h) { + return new LinkedHashMap(h); + } + }, new F, Hashtable>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Hashtable f(final LinkedHashMap m) { + return new Hashtable(m); + } + }); + } + + /** + * A shrink strategy for linked hash sets. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for linked hash sets. + */ + public static Shrink> shrinkLinkedHashSet(final Shrink sa) { + return shrinkList(sa).map(Java.List_LinkedHashSet(), Java.LinkedHashSet_List()); + } + + /** + * A shrink strategy for linked lists. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for linked lists. + */ + public static Shrink> shrinkLinkedList(final Shrink sa) { + return shrinkList(sa).map(Java.List_LinkedList(), Java.LinkedList_List()); + } + + /** + * A shrink strategy for priority queues. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for priority queues. + */ + public static Shrink> shrinkPriorityQueue(final Shrink sa) { + return shrinkList(sa).map(Java.List_PriorityQueue(), Java.PriorityQueue_List()); + } + + /** + * A shrink strategy for properties. + */ + public static final Shrink shrinkProperties = shrinkHashtable(shrinkString, shrinkString) + .map(new F, Properties>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Properties f(final Hashtable h) { + final Properties p = new Properties(); + + for (final String k : h.keySet()) { + p.setProperty(k, h.get(k)); + } + + return p; + } + }, new F>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Hashtable f(final Properties p) { + final Hashtable t = new Hashtable(); + + for (final Object s : p.keySet()) { + t.put((String) s, p.getProperty((String) s)); + } + + return t; + } + }); + + /** + * A shrink strategy for stacks. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for stacks. + */ + public static Shrink> shrinkStack(final Shrink sa) { + return shrinkList(sa).map(Java.List_Stack(), Java.Stack_List()); + } + + /** + * A shrink strategy for tree maps. + * + * @param sk The shrink strategy for keys. + * @param sv The shrink stratgey for values. + * @return A shrink strategy for tree maps. + */ + public static Shrink> shrinkTreeMap(final Shrink sk, final Shrink sv) { + return shrinkHashtable(sk, sv).map(new F, TreeMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public TreeMap f(final Hashtable h) { + return new TreeMap(h); + } + }, new F, Hashtable>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Hashtable f(final TreeMap m) { + return new Hashtable(m); + } + }); + } + + /** + * A shrink strategy for tree sets. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for tree sets. + */ + public static Shrink> shrinkTreeSet(final Shrink sa) { + return shrinkList(sa).map(Java.List_TreeSet(), Java.TreeSet_List()); + } + + /** + * A shrink strategy for vectors. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for vectors. + */ + public static Shrink> shrinkVector(final Shrink sa) { + return shrinkList(sa).map(Java.List_Vector(), Java.Vector_List()); + } + + /** + * A shrink strategy for weak hash maps. + * + * @param sk The shrink strategy for keys. + * @param sv The shrink stratgey for values. + * @return A shrink strategy for weak hash maps. + */ + public static Shrink> shrinkWeakHashMap(final Shrink sk, final Shrink sv) { + return shrinkHashtable(sk, sv).map(new F, WeakHashMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public WeakHashMap f(final Hashtable h) { + return new WeakHashMap(h); + } + }, new F, Hashtable>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Hashtable f(final WeakHashMap m) { + return new Hashtable(m); + } + }); + } + + // END java.util + + // BEGIN java.util.concurrent + + /** + * A shrink strategy for array blocking queues. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for array blocking queues. + */ + public static Shrink> shrinkArrayBlockingQueue(final Shrink sa) { + return shrinkList(sa).map(Java.List_ArrayBlockingQueue(false), Java.ArrayBlockingQueue_List()); + } + + /** + * A shrink strategy for concurrent hash maps. + * + * @param sk The shrink strategy for keys. + * @param sv The shrink stratgey for values. + * @return A shrink strategy for concurrent hash maps. + */ + public static Shrink> shrinkConcurrentHashMap(final Shrink sk, final Shrink sv) { + return shrinkHashtable(sk, sv).map(new F, ConcurrentHashMap>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public ConcurrentHashMap f(final Hashtable h) { + return new ConcurrentHashMap(h); + } + }, new F, Hashtable>() { + @SuppressWarnings({"UseOfObsoleteCollectionType"}) + public Hashtable f(final ConcurrentHashMap m) { + return new Hashtable(m); + } + }); + } + + /** + * A shrink strategy for concurrent linked queues. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for concurrent linked queues. + */ + public static Shrink> shrinkConcurrentLinkedQueue(final Shrink sa) { + return shrinkList(sa).map(Java.List_ConcurrentLinkedQueue(), Java.ConcurrentLinkedQueue_List()); + } + + /** + * A shrink strategy for copy on write array lists. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for copy on write array lists. + */ + public static Shrink> shrinkCopyOnWriteArrayList(final Shrink sa) { + return shrinkList(sa).map(Java.List_CopyOnWriteArrayList(), Java.CopyOnWriteArrayList_List()); + } + + /** + * A shrink strategy for copy on write array sets. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for copy on write array sets. + */ + public static Shrink> shrinkCopyOnWriteArraySet(final Shrink sa) { + return shrinkList(sa).map(Java.List_CopyOnWriteArraySet(), Java.CopyOnWriteArraySet_List()); + } + + /** + * A shrink strategy for delay queues. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for delay queues. + */ + public static Shrink> shrinkDelayQueue(final Shrink sa) { + return shrinkList(sa).map(Java.List_DelayQueue(), Java.DelayQueue_List()); + } + + /** + * A shrink strategy for linked blocking queues. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for linked blocking queues. + */ + public static Shrink> shrinkLinkedBlockingQueue(final Shrink sa) { + return shrinkList(sa).map(Java.List_LinkedBlockingQueue(), Java.LinkedBlockingQueue_List()); + } + + /** + * A shrink strategy for priority blocking queues. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for priority blocking queues. + */ + public static Shrink> shrinkPriorityBlockingQueue(final Shrink sa) { + return shrinkList(sa).map(Java.List_PriorityBlockingQueue(), Java.PriorityBlockingQueue_List()); + } + + /** + * A shrink strategy for synchronous queues. + * + * @param sa The shrink strategy for the elements. + * @return A shrink strategy for synchronous queues. + */ + public static Shrink> shrinkSynchronousQueue(final Shrink sa) { + return shrinkList(sa).map(Java.List_SynchronousQueue(false), Java.SynchronousQueue_List()); + } + + // END java.util.concurrent + + // BEGIN java.sql + + /** + * A shrink strategy for SQL dates. + */ + public static final Shrink shrinkSQLDate = + shrinkLong.map(new F() { + public java.sql.Date f(final Long i) { + return new java.sql.Date(i); + } + }, new F() { + public Long f(final java.sql.Date c) { + return c.getTime(); + } + }); + + /** + * A shrink strategy for SQL times. + */ + public static final Shrink Shrink> shrinkP1(final Shrink sa) { + return new Shrink>(new F, Stream>>() { + public Stream> f(final P1 p) { + return sa.shrink(p._1()).map(new F>() { + public P1 f(final A a) { + return p(a); + } + }); + } + }); + } + + /** + * Returns a shrinking strategy for product-2 values. + * + * @param sa The shrinking strategy for the values. + * @param sb The shrinking strategy for the values. + * @return a shrinking strategy for product-2 values. + */ + public static Shrink> shrinkP2(final Shrink sa, final Shrink sb) { + return new Shrink>(new F, Stream>>() { + public Stream> f(final P2 p) { + final F>> p2 = p2(); + return sa.shrink(p._1()).bind(sb.shrink(p._2()), p2); + } + }); + } + + /** + * Returns a shrinking strategy for product-3 values. + * + * @param sa The shrinking strategy for the values. + * @param sb The shrinking strategy for the values. + * @param sc The shrinking strategy for the values. + * @return a shrinking strategy for product-3 values. + */ + public static Shrink> shrinkP3(final Shrink sa, final Shrink sb, final Shrink sc) { + return new Shrink>(new F, Stream>>() { + public Stream> f(final P3 p) { + final F>>> p3 = p3(); + return sa.shrink(p._1()).bind(sb.shrink(p._2()), sc.shrink(p._3()), p3); + } + }); + } + + /** + * Returns a shrinking strategy for product-4 values. + * + * @param sa The shrinking strategy for the values. + * @param sb The shrinking strategy for the values. + * @param sc The shrinking strategy for the values. + * @param sd The shrinking strategy for the values. + * @return a shrinking strategy for product-4 values. + */ + public static Shrink> shrinkP4(final Shrink sa, final Shrink sb, final Shrink sc, + final Shrink sd) { + return new Shrink>(new F, Stream>>() { + public Stream> f(final P4 p) { + final F>>>> p4 = p4(); + return sa.shrink(p._1()).bind(sb.shrink(p._2()), sc.shrink(p._3()), sd.shrink(p._4()), p4); + } + }); + } + + /** + * Returns a shrinking strategy for product-5 values. + * + * @param sa The shrinking strategy for the values. + * @param sb The shrinking strategy for the values. + * @param sc The shrinking strategy for the values. + * @param sd The shrinking strategy for the values. + * @param se The shrinking strategy for the values. + * @return a shrinking strategy for product-5 values. + */ + public static Shrink> shrinkP5(final Shrink sa, final Shrink sb, + final Shrink sc, final Shrink sd, + final Shrink se) { + return new Shrink>(new F, Stream>>() { + public Stream> f(final P5 p) { + final F>>>>> p5 = p5(); + return sa.shrink(p._1()).bind(sb.shrink(p._2()), sc.shrink(p._3()), sd.shrink(p._4()), se.shrink(p._5()), p5); + } + }); + } + + /** + * Returns a shrinking strategy for product-6 values. + * + * @param sa The shrinking strategy for the values. + * @param sb The shrinking strategy for the values. + * @param sc The shrinking strategy for the values. + * @param sd The shrinking strategy for the values. + * @param se The shrinking strategy for the values. + * @param sf The shrinking strategy for the values. + * @return a shrinking strategy for product-6 values. + */ + public static Shrink> shrinkP6(final Shrink sa, final Shrink sb, + final Shrink sc, final Shrink sd, + final Shrink se, final Shrink sf) { + return new Shrink>(new F, Stream>>() { + public Stream> f(final P6 p) { + final F>>>>>> p6 = p6(); + return sa.shrink(p._1()) + .bind(sb.shrink(p._2()), sc.shrink(p._3()), sd.shrink(p._4()), se.shrink(p._5()), sf.shrink(p._6()), p6); + } + }); + } + + /** + * Returns a shrinking strategy for product-7 values. + * + * @param sa The shrinking strategy for the values. + * @param sb The shrinking strategy for the values. + * @param sc The shrinking strategy for the values. + * @param sd The shrinking strategy for the values. + * @param se The shrinking strategy for the values. + * @param sf The shrinking strategy for the values. + * @param sg The shrinking strategy for the values. + * @return a shrinking strategy for product-7 values. + */ + public static Shrink> shrinkP7(final Shrink sa, final Shrink sb, + final Shrink sc, final Shrink sd, + final Shrink se, + final Shrink sf, + final Shrink sg) { + return new Shrink>(new F, Stream>>() { + public Stream> f(final P7 p) { + final F>>>>>>> p7 = p7(); + return sa.shrink(p._1()) + .bind(sb.shrink(p._2()), sc.shrink(p._3()), sd.shrink(p._4()), se.shrink(p._5()), sf.shrink(p._6()), + sg.shrink(p._7()), p7); + } + }); + } + + /** + * Returns a shrinking strategy for product-8 values. + * + * @param sa The shrinking strategy for the values. + * @param sb The shrinking strategy for the values. + * @param sc The shrinking strategy for the values. + * @param sd The shrinking strategy for the values. + * @param se The shrinking strategy for the values. + * @param sf The shrinking strategy for the values. + * @param sg The shrinking strategy for the values. + * @param sh The shrinking strategy for the values. + * @return a shrinking strategy for product-8 values. + */ + public static Shrink> shrinkP8(final Shrink sa, + final Shrink sb, + final Shrink sc, + final Shrink sd, + final Shrink se, + final Shrink sf, + final Shrink sg, + final Shrink sh) { + return new Shrink>( + new F, Stream>>() { + public Stream> f(final P8 p) { + final F>>>>>>>> p8 = p8(); + return sa.shrink(p._1()) + .bind(sb.shrink(p._2()), sc.shrink(p._3()), sd.shrink(p._4()), se.shrink(p._5()), sf.shrink(p._6()), + sg.shrink(p._7()), sh.shrink(p._8()), p8); + } + }); + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/Variant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/Variant.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,93 @@ +package fj.test; + +import fj.F; +import static fj.test.Gen.gen; + +import java.util.HashMap; + +/** + * A memoised generator variant. Stores generators that have already been computed for the given arguments. + * + * @version %build.number% + */ +public final class Variant { + private static final HashMap> variantMemo = new HashMap>(); + + private static final class LongGen { + private final long n; + private final Gen gen; + + LongGen(final long n, final Gen gen) { + this.n = n; + this.gen = gen; + } + + public boolean equals(final Object o) { + return o != null && + o.getClass() == LongGen.class && + n == ((LongGen)o).n && + gen == ((LongGen)o).gen; + } + + public int hashCode() { + final int p = 419; + int result = 239; + result = p * result + (int) (n ^ n >>> 32); + result = p * result + gen.hashCode(); + return result; + } + } + + private Variant() { + throw new UnsupportedOperationException(); + } + + /** + * Produces a generator that is independent of the given generator using the given value. + * + * @param n The value to produce the new generator from. + * @param g The generator to produce the new generator from. + * @return A generator that is independent of the given generator using the given value. + */ + public static Gen variant(final long n, final Gen g) { + final LongGen p = new LongGen(n, g); + final Gen gx = variantMemo.get(p); + if(gx == null) { + final Gen t = gen(new F>() { + public F f(final Integer i) { + return new F() { + public A f(final Rand r) { + return g.gen(i, r.reseed(n)); + } + }; + } + }); + variantMemo.put(p, t); + return t; + } else return gen(new F>() { + public F f(final Integer i) { + return new F() { + @SuppressWarnings({"unchecked"}) + public A f(final Rand r) { + return (A)gx.gen(i, r); + } + }; + } + }); + } + + /** + * A curried version of {@link #variant(long, Gen)}. + * + * @param n The value to produce the new generator from. + * @return A curried version of {@link #variant(long, Gen)}. + */ + public static F, Gen> variant(final long n) { + return new F, Gen>() { + public Gen f(final Gen g) { + return variant(n, g); + } + }; + } +} + diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/package-info.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,18 @@ +/** + * Reductio is a software package that provides automated specification-based testing and + * is intended to replace traditional testing techniques that have very little automation. Reductio + * encourages users to express properties or theorems about their software, and + * the testing and reporting of the status of those properties occurs by automating various aspects. + * For example, if a property is found to be false (i.e. a test fails), then the counter-example may + * be reduced while still falsifying the property so that the reported counter-example is the + * simplest found (this is called {@link fj.test.Shrink}). The expression of the property also + * serves as very rigorous documentation for the code under test; far surpassing that provided by + * traditional testing techniques. + * + * Many of the concepts of Reductio originated with a paper called QuickCheck: A Lightweight Tool + * for Random Testing of Haskell Programs by Koen Claassen and John Hughes from Chalmers University + * of Technology. Reductio also borrows ideas from ScalaCheck by Rickard Nilsson. + * + * @version %build.number% + */ +package fj.test; diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/reflect/Category.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/reflect/Category.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,30 @@ +package fj.test.reflect; + +import fj.test.Property; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specifies the categories of a {@link Property property}, which are the union of + * categories specified on the enclosing class and the categories specified on the method or field + * that make up the property. + * + * @version %build.number% + */ +@Documented +@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface Category { + /** + * The categories of the property. + * + * @return The categories of the property. + */ + String[] value(); +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/reflect/Check.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/reflect/Check.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,344 @@ +package fj.test.reflect; + +import static fj.Bottom.error; +import fj.Class; +import static fj.Class.clas; +import fj.F; +import fj.Function; +import fj.P; +import static fj.P.p; +import fj.P2; +import fj.P3; +import fj.data.Array; +import static fj.data.Array.array; +import fj.data.List; +import static fj.data.List.join; +import static fj.data.List.list; +import fj.data.Option; +import static fj.data.Option.fromNull; +import static fj.data.Option.none; +import static fj.data.Option.some; +import static fj.data.Option.somes; +import fj.test.CheckResult; +import fj.test.Property; +import fj.test.Rand; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import static java.lang.reflect.Modifier.isStatic; + +/** + * Functions for checking properties in a class that are found reflectively and according to various + * annotations. + * + * @version %build.number% + */ +public final class Check { + private Check() { + throw new UnsupportedOperationException(); + } + + /** + * Returns the results and names of checking the properties on the given classes using a + * {@link Rand#standard standard random generator}. + * + * @param c The classes to check the properties of. + * @param categories The categories of properties to return. If no categories are specified, all + * candidate properties are returned, otherwise, only those properties in the given categories are + * returned (properties in no category are omitted in this latter case). + * @return The results and names of checking the properties on the given classes using a + * {@link Rand#standard standard random generator}. + */ + public static List> check(final List> c, final String... categories) { + return check(c, Rand.standard, categories); + } + + /** + * Returns the results and names of checking the properties on the given classes using a + * {@link Rand#standard standard random generator}. + * + * @param c The classes to check the properties of. + * @param categories The categories of properties to return. If no categories are specified, all + * candidate properties are returned, otherwise, only those properties in the given categories are + * returned (properties in no category are omitted in this latter case). + * @return The results and names of checking the properties on the given classes using a + * {@link Rand#standard standard random generator}. + */ + public static List> check(final List> c, final List categories) { + return check(c, Rand.standard, categories.toArray().array(String[].class)); + } + + /** + * Returns the results and names of checking the properties on the given classes. + * + * @param c The classes to check the properties of. + * @param r The random generator to use to check the properties on the given classes. + * @param categories The categories of properties to return. If no categories are specified, all + * candidate properties are returned, otherwise, only those properties in the given categories are + * returned (properties in no category are omitted in this latter case). + * @return The results and names of checking the properties on the given classes. + */ + public static List> check(final List> c, final Rand r, final String... categories) { + return join(c.map(new F, List>>() { + public List> f(final java.lang.Class c) { + return check(c, r, categories); + } + })); + } + + /** + * Returns the results and names of checking the properties on the given classes. + * + * @param c The classes to check the properties of. + * @param r The random generator to use to check the properties on the given classes. + * @param categories The categories of properties to return. If no categories are specified, all + * candidate properties are returned, otherwise, only those properties in the given categories are + * returned (properties in no category are omitted in this latter case). + * @return The results and names of checking the properties on the given classes. + */ + public static List> check(final List> c, final Rand r, final List categories) { + return check(c, r, categories.toArray().array(String[].class)); + } + + /** + * Returns the results and names of checking the properties on the given class using a + * {@link Rand#standard standard random generator}. + * + * @param c The class to check the properties of. + * @param categories The categories of properties to return. If no categories are specified, all + * candidate properties are returned, otherwise, only those properties in the given categories are + * returned (properties in no category are omitted in this latter case). + * @return The results and names of checking the properties on the given class using a + * {@link Rand#standard standard random generator}. + */ + public static List> check(final java.lang.Class c, final String... categories) { + return check(c, Rand.standard, categories); + } + + /** + * Returns the results and names of checking the properties on the given class using a + * {@link Rand#standard standard random generator}. + * + * @param c The class to check the properties of. + * @param categories The categories of properties to return. If no categories are specified, all + * candidate properties are returned, otherwise, only those properties in the given categories are + * returned (properties in no category are omitted in this latter case). + * @return The results and names of checking the properties on the given class using a + * {@link Rand#standard standard random generator}. + */ + public static List> check(final java.lang.Class c, final List categories) { + return check(c, Rand.standard, categories.toArray().array(String[].class)); + } + + /** + * Returns the results and names of checking the properties on the given class. + * + * @param c The class to check the properties of. + * @param r The random generator to use to check the properties on the given class. + * @param categories The categories of properties to return. If no categories are specified, all + * candidate properties are returned, otherwise, only those properties in the given categories are + * returned (properties in no category are omitted in this latter case). + * @return The results of checking the properties on the given class. + */ + public static List> check(final java.lang.Class c, final Rand r, final String... categories) { + return join(clas(c).inheritance().map(new F, List>>>() { + public List>> f(final Class c) { + return properties(c.clas(), categories); + } + })).map(new F>, P2>() { + public P2 f(final P3> p) { + if(p._3().isSome()) { + final CheckParams ps = p._3().some(); + return p(p._2(), p._1().check(r, ps.minSuccessful(), ps.maxDiscarded(), ps.minSize(), ps.maxSize())); + } else + return p(p._2(), p._1().check(r)); + } + }); + } + + /** + * Returns the results and names of checking the properties on the given class. + * + * @param c The class to check the properties of. + * @param r The random generator to use to check the properties on the given class. + * @param categories The categories of properties to return. If no categories are specified, all + * candidate properties are returned, otherwise, only those properties in the given categories are + * returned (properties in no category are omitted in this latter case). + * @return The results of checking the properties on the given class. + */ + public static List> check(final java.lang.Class c, final Rand r, final List categories) { + return check(c, r, categories.toArray().array(String[].class)); + } + + /** + * Returns all properties, their name and possible check parameters in a given class that are + * found reflectively and according to various annotations. For example, properties or their + * enclosing class that are annotated with {@link NoCheck} are not considered. The name of a + * property is specified by the {@link Name annotation} or if this annotation is not present, the + * name of the method or field that represents the property. + * + * @param c The class to look for properties on. + * @param categories The categories of properties to return. If no categories are specified, all + * candidate properties are returned, otherwise, only those properties in the given categories are + * returned (properties in no category are omitted in this latter case). + * @return All properties, their name and possible check parameters in a given class that are + * found reflectively and according to various annotations. + */ + public static List>> properties(final java.lang.Class c, final String... categories) { + //noinspection ClassEscapesDefinedScope + final Array>> propFields = properties(array(c.getDeclaredFields()).map(new F() { + public PropertyMember f(final Field f) { + return new PropertyMember() { + public java.lang.Class type() { + return f.getType(); + } + + public AnnotatedElement element() { + return f; + } + + public String name() { + return f.getName(); + } + + public int modifiers() { + return f.getModifiers(); + } + + public Property invoke(final X x) throws IllegalAccessException { + f.setAccessible(true); + return (Property)f.get(x); + } + + public boolean isProperty() { + return true; + } + }; + } + }), c, categories); + + //noinspection ClassEscapesDefinedScope + final Array>> propMethods = properties(array(c.getDeclaredMethods()).map(new F() { + public PropertyMember f(final Method m) { + //noinspection ProhibitedExceptionDeclared + return new PropertyMember() { + public java.lang.Class type() { + return m.getReturnType(); + } + + public AnnotatedElement element() { + return m; + } + + public String name() { + return m.getName(); + } + + public int modifiers() { + return m.getModifiers(); + } + + public Property invoke(final X x) throws Exception { + m.setAccessible(true); + return (Property)m.invoke(x); + } + + public boolean isProperty() { + return m.getParameterTypes().length == 0; + } + }; + } + }), c, categories); + + return propFields.append(propMethods).toList(); + } + + private interface PropertyMember { + java.lang.Class type(); + AnnotatedElement element(); + String name(); + int modifiers(); + @SuppressWarnings({"ProhibitedExceptionDeclared"}) + Property invoke(X x) throws Exception; + boolean isProperty(); + } + + private static Array>> properties(final Array ms, final java.lang.Class declaringClass, final String... categories) { + final Option t = emptyCtor(declaringClass).map(new F, T>() { + @SuppressWarnings({"OverlyBroadCatchBlock"}) + public T f(final Constructor ctor) { + try { + ctor.setAccessible(true); + return ctor.newInstance(); + } catch(Exception e) { + throw error(e.toString()); + } + } + }); + + final F> p = new F>() { + public F f(final AnnotatedElement e) { + return new F() { + public Boolean f(final String s) { + final F p = new F() { + public Boolean f(final Category c) { + return array(c.value()).exists(new F() { + public Boolean f(final String cs) { + return cs.equals(s); + } + }); + } + }; + + @SuppressWarnings("unchecked") + final List bss = somes(list(fromNull(e.getAnnotation(Category.class)).map(p), + fromNull(declaringClass.getAnnotation(Category.class)).map(p))); + return bss.exists(Function.identity()); + } + }; + } + }; + + final F nameS = new F() { + public String f(final Name name) { + return name.value(); + } + }; + + return ms.filter(new F() { + public Boolean f(final PropertyMember m) { + //noinspection ObjectEquality + return m.isProperty() && + m.type() == Property.class && + !m.element().isAnnotationPresent(NoCheck.class) && + !declaringClass.isAnnotationPresent(NoCheck.class) && + (categories.length == 0 || array(categories).exists(p.f(m.element()))) && + (t.isSome() || isStatic(m.modifiers())); + } + }).map(new F>>() { + public P3> f(final PropertyMember m) { + try { + final Option params = fromNull(m.element().getAnnotation(CheckParams.class)).orElse(fromNull(declaringClass.getAnnotation(CheckParams.class))); + final String name = fromNull(m.element().getAnnotation(Name.class)).map(nameS).orSome(m.name()); + return p(m.invoke(t.orSome(P.p(null))), name, params); + } catch(Exception e) { + throw error(e.toString()); + } + } + }); + } + + private static Option> emptyCtor(final java.lang.Class c) { + Option> ctor; + + //noinspection UnusedCatchParameter + try { + ctor = some(c.getDeclaredConstructor()); + } catch(NoSuchMethodException e) { + ctor = none(); + } + return ctor; + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/reflect/CheckParams.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/reflect/CheckParams.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,52 @@ +package fj.test.reflect; + +import fj.P1; +import fj.test.Property; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specifies the check parameters on a {@link Property} property with typical defaults. + * + * @version %build.number% + */ +@Documented +@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface CheckParams { + /** + * The minimum number of successful tests before a result is reached. + * + * @return The minimum number of successful tests before a result is reached. + */ + int minSuccessful() default 100; + + /** + * The maximum number of tests discarded because they did not satisfy pre-conditions + * (i.e. {@link Property#implies(boolean, P1)}). + * + * @return The maximum number of tests discarded because they did not satisfy pre-conditions + * (i.e. {@link Property#implies(boolean, P1)}). + */ + int maxDiscarded() default 500; + + /** + * The minimum size to use for checking. + * + * @return The minimum size to use for checking. + */ + int minSize() default 0; + + /** + * The maximum size to use for checking. + * + * @return The maximum size to use for checking. + */ + int maxSize() default 100; +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/reflect/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/reflect/Main.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,52 @@ +package fj.test.reflect; + +import fj.P2; +import static fj.data.Array.array; + +import fj.function.Effect1; +import fj.test.CheckResult; +import static fj.test.CheckResult.summary; +import static fj.test.reflect.Check.check; + +import static java.lang.Class.forName; +import static java.lang.System.exit; +import static java.lang.System.out; + +/** + * Checks the properties of a class using a standard random generator, standard check parameters and + * the given categories. The class name and categories are passed as command line arguments. + * + * @version %build.number% + */ +public final class Main { + private Main() { + throw new UnsupportedOperationException(); + } + + /** + * Check the given class and categories. At least one command line argument (the class name) must be + * passed or an error message results. + * + * @param args The class name as the first argument, then zero or more categories. + */ + public static void main(final String... args) { + if(args.length == 0) { + System.err.println(" [category]*"); + //noinspection CallToSystemExit + exit(441); + } else { + try { + check(forName(args[0]), array(args).toList().tail()).foreachDoEffect(new Effect1>() { + public void f(final P2 r) { + summary.print(r._2()); + out.println(" (" + r._1() + ')'); + } + }); + } catch(ClassNotFoundException e) { + System.err.println(e); + //noinspection CallToSystemExit + exit(144); + } + } + } +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/reflect/Name.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/reflect/Name.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,26 @@ +package fj.test.reflect; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The name of a property to be used in reporting. + * + * @version %build.number% + */ +@Documented +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface Name { + /** + * The name of a property to be used in reporting. + * + * @return The name of a property to be used in reporting. + */ + String value(); +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/reflect/NoCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/reflect/NoCheck.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,21 @@ +package fj.test.reflect; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Denotes that a property should be excluded from any checking. + * + * @version %build.number% + */ +@Documented +@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface NoCheck { + +} diff -r 000000000000 -r fe80c1edf1be src/main/java/fj/test/reflect/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/test/reflect/package-info.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,36 @@ +/** + * A wrapper around the fj.test package that uses annotations for configuring properties to + * check. The properties are found using reflection. All annotations + * are optional and a property is eligible for checking by default. A property is any of the + * following member descriptions, unless the member or enclosing class is annotated with + * {@link fj.test.reflect.NoCheck}. + * +
    +
  • a static field of type {@link fj.test.Property}.
  • +
  • a static zero argument method that returns {@link fj.test.Property}.
  • +
  • a non-static field of type {@link fj.test.Property} in a class with a zero-argument constructor.
  • +
  • a non-static no-argument method that returns {@link fj.test.Property} in a class with a no-argument + constructor.
  • +
+ * + *

+ * A property may be in zero or more categories by annotating the member or enclosing class with + * {@link fj.test.reflect.Category}. The property is in the set of categories that make up the + * union of its member and enclosing class category annotation. + *

+ *

+ * When a property is checked, it uses default configuration values, which may be overridden by + * annotating the member or the enclosing class with the {@link fj.test.reflect.CheckParams} + * annotation. The values used are first those specified on the member; or if the annotation does + * not exist, then the enclosing class (default values otherwise). + *

+ *

+ * A property can have a name associated with it by annotating the member with the + * {@link fj.test.reflect.Name} annotation. The name is a {@link java.lang.String} that is used + * only for reporting in check results. If the {@link fj.test.reflect.Name} annotation does not + * appear on a property member, then the field or method name is used by default. + *

+ * + * @version %build.number% + */ +package fj.test.reflect; diff -r 000000000000 -r fe80c1edf1be src/test/java/fj/MemoisationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/fj/MemoisationTest.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,110 @@ +package fj; + +import fj.test.Property; +import org.junit.Test; + +import static fj.test.Arbitrary.arbInteger; +import static fj.test.CheckResult.summary; +import static fj.test.Property.prop; +import static fj.test.Property.property; +import static org.junit.Assert.assertTrue; + +/** + * Created by mperry on 14/07/2014. + */ +public class MemoisationTest { + + @Test + public void test1() { + final Property p = property(arbInteger, a -> { + P1 t = P.p(a).memo(); + return prop(t._1() == t._1()); + }); + summary.println(p.check()); + } + + @Test + public void test2() { + final Property p = property(arbInteger, arbInteger, (a, b) -> { + P2 t = P.p(a, b).memo(); + return prop(t._1() == t._1() && t._2() == t._2()); + }); + summary.println(p.check()); + } + + static P2 pair = P.p(0, 0); + + static Integer count(int i) { + if (i == 1) { + pair = P.p(pair._1() + 1, pair._2()); + return pair._1(); + } else if (i == 2) { + pair = P.p(pair._1(), pair._2() + 1); + return pair._2(); + } else { + return -1; + } + } + + @Test + public void testRecomputeP2() { + P2 t = P.lazy(u -> count(1), u -> count(2)).memo(); + System.out.println("tuple: " + t + " 1:" + t._1() + " 2: " + t._2()); + assertTrue(t._1() == t._1() && t._2() == t._2()); + } + + @Test + public void test3() { + final Property p = property(arbInteger, arbInteger, arbInteger, (a, b, c) -> { + P3 t = P.p(a, b, c).memo(); + return prop(t._1() == t._1() && t._2() == t._2() && t._3() == t._3()); + }); + summary.println(p.check()); + } + + @Test + public void test4() { + final Property p = property(arbInteger, arbInteger, arbInteger, arbInteger, (a, b, c, d) -> { + P4 t = P.p(a, b, c, d).memo(); + return prop(t._1() == t._1() && t._2() == t._2() && t._3() == t._3() && t._4() == t._4()); + }); + summary.println(p.check()); + } + + @Test + public void test5() { + final Property p = property(arbInteger, arbInteger, arbInteger, arbInteger, arbInteger, (a, b, c, d, e) -> { + P5 t = P.p(a, b, c, d, e).memo(); + return prop(t._1() == t._1() && t._2() == t._2() && t._3() == t._3() && t._4() == t._4() && t._5() == t._5()); + }); + summary.println(p.check()); + } + + @Test + public void test6() { + final Property p = property(arbInteger, arbInteger, arbInteger, arbInteger, arbInteger, arbInteger, (a, b, c, d, e, f) -> { + P6 t = P.p(a, b, c, d, e, f).memo(); + return prop(t._1() == t._1() && t._2() == t._2() && t._3() == t._3() && t._4() == t._4() && t._5() == t._5() && t._6() == t._6()); + }); + summary.println(p.check()); + } + + @Test + public void test7() { + final Property p = property(arbInteger, arbInteger, arbInteger, arbInteger, arbInteger, arbInteger, arbInteger, (a, b, c, d, e, f, g) -> { + P7 t = P.p(a, b, c, d, e, f, g).memo(); + return prop(t._1() == t._1() && t._2() == t._2() && t._3() == t._3() && t._4() == t._4() && t._5() == t._5() && t._6() == t._6() && t._7() == t._7()); + }); + summary.println(p.check()); + } + + @Test + public void test8() { + final Property p = property(arbInteger, arbInteger, arbInteger, arbInteger, arbInteger, arbInteger, arbInteger, arbInteger, (a, b, c, d, e, f, g, h) -> { + P8 t = P.p(a, b, c, d, e, f, g, h).memo(); + return prop(t._1() == t._1() && t._2() == t._2() && t._3() == t._3() && t._4() == t._4() && t._5() == t._5() && t._6() == t._6() && t._7() == t._7() && t._8() == t._8()); + }); + summary.println(p.check()); + } + +} diff -r 000000000000 -r fe80c1edf1be src/test/java/fj/P2Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/fj/P2Test.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,17 @@ +package fj; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Created by MarkPerry on 22/07/2014. + */ +public class P2Test { + + @Test + public void testToString() { + String s = P.p(1, 2).toString(); + Assert.assertTrue(s.equals("(1,2)")); + } + +} diff -r 000000000000 -r fe80c1edf1be src/test/java/fj/data/JavaTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/fj/data/JavaTest.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,26 @@ +package fj.data; + +import fj.Show; +import org.junit.Test; + +import java.util.EnumSet; + +import static fj.Show.listShow; + +/** + * Created by MarkPerry on 14/07/2014. + */ +public class JavaTest { + + @Test + public void test1() { + // #33: Fixes ClassCastException + final List colors = Java.EnumSet_List().f(EnumSet.allOf(Colors.class)); + listShow(Show.anyShow()).print(colors); + } + + enum Colors { + red, green, blue + } + +} diff -r 000000000000 -r fe80c1edf1be src/test/java/fj/data/ReaderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/fj/data/ReaderTest.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,116 @@ +package fj.data; + +import fj.F; +import fj.data.test.PropertyAssert; +import fj.test.*; +import org.junit.Test; + +import static fj.F1Functions.bind; +import static fj.F1Functions.map; +import static fj.test.Arbitrary.*; +import static fj.test.Coarbitrary.coarbInteger; +import static fj.test.Property.prop; +import static fj.test.Property.property; +import static org.junit.Assert.assertTrue; + +/** + * Created by MarkPerry on 4/12/2014. + */ +public class ReaderTest { + + @Test + public void testMap() { + // (3 + 8) * 11 + // example taken from http://learnyouahaskell.com/for-a-few-monads-more + int x = Reader.unit((Integer i) -> i + 3).map(i -> i * 5).f(8); + assertTrue(x == 55); +// System.out.println(x); // 55 + } + + @Test + public void testFlatMap() { + // (3 * 2) + (3 + 10) + // example taken from http://learnyouahaskell.com/for-a-few-monads-more + int y = (int) Reader.unit((Integer i) -> i * 2).flatMap(a -> Reader.unit((Integer i) -> i + 10).map(b -> a + b)).f(3); +// System.out.println(y); // 19 + assertTrue(y == 19); + } + + @Test + public void testMapProp() { + Property p = property( + arbF(coarbInteger, arbInteger), + arbF(coarbInteger, arbInteger), + arbInteger, + (f, g, i) -> { + int expected = map(f, g).f(i); +// System.out.println(String.format("input: %d, result: %d", i, expected)); + return prop(expected == Reader.unit(f).map(g).f(i)); + }); + PropertyAssert.assertResult(p); + } + + @Test + public void testFlatMapProp() { + Arbitrary>> a = arbF(coarbInteger, arbReader()); + Property p = property( + arbF(coarbInteger, arbInteger), + a, + arbInteger, + (f, g, i) -> { + int expected = bind(f, j -> g.f(j).getFunction()).f(i); +// System.out.println(String.format("input: %d, result: %d", i, expected)); + return prop(expected == Reader.unit(f).flatMap(g).f(i)); + } + ); + PropertyAssert.assertResult(p); + } + + // Left identity: return a >>= f == f a + @Test + public void testLeftIdentity() { + Property p = Property.property( + arbInteger, + arbInteger, + arbF(coarbInteger, arbReader()), + (i, j, f) -> { + int a = Reader.constant(i).flatMap(f).f(j); + int b = f.f(i).f(j); + return prop(a == b); + }); + PropertyAssert.assertResult(p); + } + + // Right identity: m >>= return == m + @Test + public void testRightIdentity() { + Property p = Property.property( + arbInteger, + arbReader(), + (i, r2) -> { + return prop(r2.flatMap(a -> Reader.constant(a)).f(i) == r2.f(i)); + }); + PropertyAssert.assertResult(p); + } + + // Associativity: (m >>= f) >>= g == m >>= (\x -> f x >>= g) + @Test + public void testAssociativity() { + Property p = Property.property( + arbInteger, + arbReader(), + arbF(coarbInteger, arbReader()), + arbF(coarbInteger, arbReader()), + (i, r, f, g) -> { + boolean b2 = r.flatMap(f).flatMap(g).f(i) == r.flatMap(x -> f.f(x).flatMap(g)).f(i); + return prop(b2); + }); + PropertyAssert.assertResult(p); + } + + public Arbitrary> arbReader() { + return Arbitrary.arbReader(coarbInteger, arbInteger); + } + + +} diff -r 000000000000 -r fe80c1edf1be src/test/java/fj/data/StateTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/fj/data/StateTest.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,15 @@ +package fj.data; + +import org.junit.Test; + +/** + * Created by MarkPerry on 18/12/2014. + */ +public class StateTest { + + @Test + public void map() { + + } + +} diff -r 000000000000 -r fe80c1edf1be src/test/java/fj/data/TestRngState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/fj/data/TestRngState.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,149 @@ +package fj.data; + +import fj.*; +import fj.test.Arbitrary; +import fj.test.Coarbitrary; +import fj.test.Gen; +import fj.test.Property; +import org.junit.Assert; +import org.junit.Test; + +import static fj.data.Option.some; +import static fj.data.Stream.unfold; +import static fj.data.test.PropertyAssert.assertResult; +import static fj.test.Arbitrary.*; +import static fj.test.Coarbitrary.coarbInteger; +import static fj.test.Property.prop; +import static fj.test.Property.property; +import static fj.test.Variant.variant; + +/** + * Created by mperry on 4/08/2014. + */ +public class TestRngState { + + static String expected1 = "<4,4,2,2,2,5,3,3,1,5>"; + static int size = 10; + + static Rng defaultRng() { + return new LcgRng(1); + } + + static P2 num(Rng r) { + return r.range(1, 5); + } + + static State defaultState() { + return State.unit(s -> num(s)); + } + + static F, State> nextState() { + return s -> s.mapState(p2 -> num(p2._1())); + } + + static P2 num(Rng r, int x) { + return r.range(x, x + 1); + } + + @Test + public void testUnfold() { + Stream s = unfold(r -> some(num(r).swap()), defaultRng()); + Assert.assertTrue(s.take(size).toList().toString().equals(expected1)); + } + + @Test + public void testTransitions() { + P2>, State> p = List.replicate(size, nextState()).foldLeft( + (P2>, State> p2, F, State> f) -> { + State s = f.f(p2._2()); + return P.p(p2._1().snoc(p2._2()), s); + } + , P.p(List.nil(), defaultState()) + ); + List ints = p._1().map(s -> s.eval(defaultRng())); + Assert.assertTrue(ints.toString().equals(expected1)); + } + + @Test + public void testSequence() { + List list = State.sequence(List.replicate(size, defaultState())).eval(defaultRng()); + Assert.assertTrue(list.toString().equals(expected1)); + } + + @Test + public void testTraverse() { + List list = State.traverse(List.range(1, 10), a -> (State.unit((Rng s) -> num(s, a)))).eval(defaultRng()); +// System.out.println(list.toString()); + String expected = "<1,2,3,5,6,7,7,9,10>"; + Assert.assertTrue(list.toString().equals(expected)); + } + + public static Arbitrary> arbState() { + return Arbitrary.arbState(Arbitrary.arbLcgRng(), Coarbitrary.coarbLcgRng(), arbInteger); + } + + public static Arbitrary>> arbStateF() { + return arbF(Coarbitrary.coarbLcgRng(), arbP2(arbLcgRng(), arbInteger)); + } + + public static Coarbitrary> coarbState() { + return Coarbitrary.coarbState(Arbitrary.arbLcgRng(), (LcgRng s, Integer j) -> (long) (j >= 0 ? 2 * j : -2 * j + 1)); + } + + public static Arbitrary>> arbBindable() { + return arbF(coarbInteger, arbState()); + } + + // Left identity: return i >>= f == f i + @Test + public void testLeftIdentity() { + Property p = property( + arbBindable(), + arbInteger, + arbLcgRng(), + (f, i, r) -> { + int a = State.constant(i).flatMap(f).eval(r); + int b = f.f(i).eval(r); +// System.out.println(String.format("a=%d, b=%d", a, b)); + return prop(a == b); + } + ); + assertResult(p); + } + + + // Right identity: m >>= return == m + @Test + public void testRightIdentity() { + Property p = Property.property( + arbState(), + arbLcgRng(), + (s, r) -> { + int x = s.flatMap(a -> State.constant(a)).eval(r); + int y = s.eval(r); +// System.out.println(String.format("x=%d, y=%d", x, y)); + return prop(x == y); + } + ); + assertResult(p); + } + + // Associativity: (m >>= f) >>= g == m >>= (\x -> f x >>= g) + @Test + public void testAssociativity() { + Property p = Property.property( + arbState(), + arbBindable(), + arbBindable(), + arbLcgRng(), + (s, f, g, r) -> { + int t = s.flatMap(f).flatMap(g).eval(r); + int u = s.flatMap(x -> f.f(x).flatMap(g)).eval(r); +// System.out.println(String.format("x=%d, y=%d", t, u)); + return prop(t == u); + }); + assertResult(p); + } + + +} diff -r 000000000000 -r fe80c1edf1be src/test/java/fj/data/TestTreeMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/fj/data/TestTreeMap.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,26 @@ +package fj.data; + +import fj.Ord; +import fj.P2; +import org.junit.Test; + +import java.util.ArrayList; + +/** + * Created by MarkPerry on 2/06/2014. + */ +public class TestTreeMap { + + @Test + public void testLargeInserts() { + // check that inserting a large number of items performs ok + // taken from https://code.google.com/p/functionaljava/issues/detail?id=31 and + // https://github.com/functionaljava/functionaljava/pull/13/files + final int n = 10000; + TreeMap m = TreeMap.empty(Ord.intOrd); + for (int i = 0; i < n; i++) { + m = m.set(i, "abc " + i); + } + } + +} diff -r 000000000000 -r fe80c1edf1be src/test/java/fj/data/WriterTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/fj/data/WriterTest.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,112 @@ +package fj.data; + +import fj.Equal; +import fj.F; +import fj.data.test.PropertyAssert; +import fj.test.Arbitrary; +import fj.test.Property; +import org.junit.Assert; +import org.junit.Test; + +import static fj.data.test.PropertyAssert.assertResult; +import static fj.test.Arbitrary.*; +import static fj.test.Coarbitrary.coarbInteger; +import static fj.test.Property.prop; +import static fj.test.Property.property; +import static org.junit.Assert.assertTrue; + +/** + * Created by MarkPerry on 17/12/2014. + */ +public class WriterTest { + + @Test + public void base() { + Assert.assertTrue(tellTruth("a", "b", 0)); + } + + boolean tellTruth(String s1, String s2, int i) { + Writer w = defaultWriter.f(i); + Writer w1 = w.tell(s1).tell(s2); + Writer w2 = w.tell(w.monoid().sum(s1, s2)); + boolean b = eq.eq(w1, w2); +// System.out.println(String.format("p1: %s, p2: %s, b: %s", w1, w2, b)); + return b; + } + + final Equal> eq = Equal.writerEqual(Equal.stringEqual, Equal.intEqual); + final F> defaultWriter = Writer.stringLogger(); + + @Test + public void testTellProp() { + Property p = property(arbString, arbString, arbInteger, (s1, s2, i) -> prop(tellTruth(s1, s2, i))); + assertResult(p); + } + + @Test + public void testMap() { + Property p = property(arbInteger, arbF(coarbInteger, arbInteger), (i, f) -> { + boolean b = eq.eq(defaultWriter.f(i).map(f), defaultWriter.f(f.f(i))); + return prop(b); + }); + assertResult(p); + } + + @Test + public void testFlatMap() { + Property p = property(arbInteger,arbF(coarbInteger, arbWriterStringInt()), (i, f) -> { + boolean b = eq.eq(Writer.stringLogger().f(i).flatMap(f), f.f(i)); + return prop(b); + }); + assertResult(p); + + } + + public Arbitrary> arbWriterStringInt() { + return arbWriterString(arbInteger); + } + + public
Arbitrary> arbWriterString(Arbitrary arb) { + return Arbitrary.arbitrary(arb.gen.map(a -> Writer.stringLogger().f(a))); + } + + // Left identity: return a >>= f == f a + @Test + public void testLeftIdentity() { + Property p = Property.property( + arbInteger, + arbF(coarbInteger, arbWriterStringInt()), + (i, f) -> { + return prop(eq.eq(defaultWriter.f(i).flatMap(f), f.f(i))); + }); + assertResult(p); + } + + // Right identity: m >>= return == m + @Test + public void testRightIdentity() { + Property p = Property.property( + arbWriterStringInt(), + (w) -> prop(eq.eq(w.flatMap(a -> defaultWriter.f(a)), w)) + ); + assertResult(p); + } + + // Associativity: (m >>= f) >>= g == m >>= (\x -> f x >>= g) + @Test + public void testAssociativity() { + Property p = Property.property( + arbWriterStringInt(), + arbF(coarbInteger, arbWriterStringInt()), + arbF(coarbInteger, arbWriterStringInt()), + (w, f, g) -> { + boolean t = eq.eq(w.flatMap(f).flatMap(g), w.flatMap(x -> f.f(x).flatMap(g))); + return prop(t); + }); + assertResult(p); + } + + + + +} diff -r 000000000000 -r fe80c1edf1be src/test/java/fj/data/test/PropertyAssert.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/fj/data/test/PropertyAssert.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,20 @@ +package fj.data.test; + +import fj.Unit; +import fj.test.CheckResult; +import fj.test.Property; +import org.junit.Assert; + +/** + * Created by MarkPerry on 18/12/2014. + */ +public class PropertyAssert { + + public static Unit assertResult(Property p) { + CheckResult cr = p.check(); + CheckResult.summary.println(cr); + Assert.assertTrue(cr.isExhausted() || cr.isPassed() || cr.isProven()); + return Unit.unit(); + } + +} diff -r 000000000000 -r fe80c1edf1be src/test/java/fj/data/test/TestCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/fj/data/test/TestCheck.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,41 @@ +package fj.data.test; + +import fj.F2; +import fj.F3; +import fj.data.List; +import fj.test.Arbitrary; +import fj.test.CheckResult; +import fj.test.Gen; +import fj.test.Property; +import org.junit.*; + +import static fj.Function.compose; +import static fj.test.Arbitrary.*; +import static fj.test.Arbitrary.arbLong; +import static fj.test.Coarbitrary.coarbInteger; +import static fj.test.Coarbitrary.coarbLong; +import static fj.test.Property.prop; +import static fj.test.Property.property; +import static org.junit.Assert.*; + +public class TestCheck { + + @Test(timeout=1000 /*ms*/) + public void testExceptionsThrownFromGeneratorsArePropagated() { + Gen failingGen = Gen.value(0).map((i) -> { + throw new RuntimeException("test failure"); + }); + + Property p = property(arbitrary(failingGen), (Integer i) -> { + return prop(i == 0); + }); + + CheckResult res = p.check( + 1, /*minSuccessful*/ + 0, /*maxDiscarded*/ + 0, /*minSize*/ + 1 /*maxSize*/ + ); + assertTrue("Exception not propagated!", res.isGenException()); + } +} diff -r 000000000000 -r fe80c1edf1be src/test/java/fj/data/test/TestNull.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/fj/data/test/TestNull.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,33 @@ +package fj.data.test; + +import fj.F2; +import fj.F3; +import fj.data.List; +import fj.test.Arbitrary; +import fj.test.CheckResult; +import fj.test.Gen; +import fj.test.Property; +import org.junit.Test; + +import static fj.Function.compose; +import static fj.test.Arbitrary.*; +import static fj.test.Arbitrary.arbLong; +import static fj.test.Coarbitrary.coarbInteger; +import static fj.test.Coarbitrary.coarbLong; +import static fj.test.Property.prop; +import static fj.test.Property.property; + +/** + * Created by MarkPerry on 3/07/2014. + */ +public class TestNull { + + @Test + public void testShowNullParameters() { + Property p = property(arbitrary(Gen.value(null)), (Integer i) -> { + return prop(i != null); + }); + CheckResult.summary.println(p.check()); + } + +} diff -r 000000000000 -r fe80c1edf1be src/test/java/fj/function/TestEffect.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/fj/function/TestEffect.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,25 @@ +package fj.function; + +import fj.F; +import org.junit.Test; + +/** + * Created by mperry on 28/08/2014. + */ +public class TestEffect { + + @Test + public void test1() { + higher(TestEffect::m1); + } + + + static void higher(Effect1 f) { + + } + + static void m1(String s) { + + } + +}