Mercurial > hg > Members > tatsuki > functionaljava-master > core
view src/main/java/fj/Equal.java @ 0:fe80c1edf1be
add getLoop
author | tatsuki |
---|---|
date | Fri, 20 Mar 2015 21:04:03 +0900 |
parents | |
children |
line wrap: on
line source
package fj; import static fj.Function.curry; import fj.data.*; import fj.data.hlist.HList; import fj.data.vector.V2; import fj.data.vector.V3; import fj.data.vector.V4; import fj.data.vector.V5; import fj.data.vector.V6; import fj.data.vector.V7; import fj.data.vector.V8; import java.math.BigInteger; import java.math.BigDecimal; /** * Tests for equality between two objects. * * @version %build.number% */ public final class Equal<A> { private final F<A, F<A, Boolean>> f; private Equal(final F<A, F<A, Boolean>> f) { this.f = f; } /** * Returns <code>true</code> if the two given arguments are equal, <code>false</code> otherwise. * * @param a1 An object to test for equality against another. * @param a2 An object to test for equality against another. * @return <code>true</code> if the two given arguments are equal, <code>false</code> otherwise. */ public boolean eq(final A a1, final A a2) { return f.f(a1).f(a2); } /** * First-class equality check. * * @return A function that returns <code>true</code> if the two given arguments are equal. */ public F2<A, A, Boolean> eq() { return new F2<A, A, Boolean>() { public Boolean f(final A a, final A a1) { return eq(a, a1); } }; } /** * Partially applied equality check. * * @param a An object to test for equality against another. * @return A function that returns <code>true</code> if the given argument equals the argument to this method. */ public F<A, Boolean> eq(final A a) { return new F<A, Boolean>() { public Boolean f(final A a1) { return eq(a, a1); } }; } /** * Maps the given function across this equal as a contra-variant functor. * * @param f The function to map. * @return A new equal. */ public <B> Equal<B> comap(final F<B, A> f) { return equal(F1Functions.o(F1Functions.o(F1Functions.<B, A, Boolean>andThen(f), this.f), f)); } /** * Constructs an equal instance from the given function. * * @param f The function to construct the equal with. * @return An equal instance from the given function. */ public static <A> Equal<A> equal(final F<A, F<A, Boolean>> f) { return new Equal<A>(f); } /** * Returns an equal instance that uses the {@link Object#equals(Object)} method to test for * equality. * * @return An equal instance that uses the {@link Object#equals(Object)} method to test for * equality. */ public static <A> Equal<A> anyEqual() { return new Equal<A>(new F<A, F<A, Boolean>>() { public F<A, Boolean> f(final A a1) { return new F<A, Boolean>() { public Boolean f(final A a2) { return a1.equals(a2); } }; } }); } /** * An equal instance for the <code>boolean</code> type. */ public static final Equal<Boolean> booleanEqual = anyEqual(); /** * An equal instance for the <code>byte</code> type. */ public static final Equal<Byte> byteEqual = anyEqual(); /** * An equal instance for the <code>char</code> type. */ public static final Equal<Character> charEqual = anyEqual(); /** * An equal instance for the <code>double</code> type. */ public static final Equal<Double> doubleEqual = anyEqual(); /** * An equal instance for the <code>float</code> type. */ public static final Equal<Float> floatEqual = anyEqual(); /** * An equal instance for the <code>int</code> type. */ public static final Equal<Integer> intEqual = anyEqual(); /** * An equal instance for the <code>BigInteger</code> type. */ public static final Equal<BigInteger> bigintEqual = anyEqual(); /** * An equal instance for the <code>BigDecimal</code> type. */ public static final Equal<BigDecimal> bigdecimalEqual = anyEqual(); /** * An equal instance for the <code>long</code> type. */ public static final Equal<Long> longEqual = anyEqual(); /** * An equal instance for the <code>short</code> type. */ public static final Equal<Short> shortEqual = anyEqual(); /** * An equal instance for the {@link String} type. */ public static final Equal<String> stringEqual = anyEqual(); /** * An equal instance for the {@link StringBuffer} type. */ public static final Equal<StringBuffer> stringBufferEqual = new Equal<StringBuffer>(new F<StringBuffer, F<StringBuffer, Boolean>>() { public F<StringBuffer, Boolean> f(final StringBuffer sb1) { return new F<StringBuffer, Boolean>() { public Boolean f(final StringBuffer sb2) { if (sb1.length() == sb2.length()) { for (int i = 0; i < sb1.length(); i++) if (sb1.charAt(i) != sb2.charAt(i)) return false; return true; } else return false; } }; } }); /** * An equal instance for the {@link StringBuilder} type. */ public static final Equal<StringBuilder> stringBuilderEqual = new Equal<StringBuilder>(new F<StringBuilder, F<StringBuilder, Boolean>>() { public F<StringBuilder, Boolean> f(final StringBuilder sb1) { return new F<StringBuilder, Boolean>() { public Boolean f(final StringBuilder sb2) { if (sb1.length() == sb2.length()) { for (int i = 0; i < sb1.length(); i++) if (sb1.charAt(i) != sb2.charAt(i)) return false; return true; } else return false; } }; } }); /** * An equal instance for the {@link Either} type. * * @param ea Equality across the left side of {@link Either}. * @param eb Equality across the right side of {@link Either}. * @return An equal instance for the {@link Either} type. */ public static <A, B> Equal<Either<A, B>> eitherEqual(final Equal<A> ea, final Equal<B> eb) { return new Equal<Either<A, B>>(new F<Either<A, B>, F<Either<A, B>, Boolean>>() { public F<Either<A, B>, Boolean> f(final Either<A, B> e1) { return new F<Either<A, B>, Boolean>() { public Boolean f(final Either<A, B> e2) { return e1.isLeft() && e2.isLeft() && ea.f.f(e1.left().value()).f(e2.left().value()) || e1.isRight() && e2.isRight() && eb.f.f(e1.right().value()).f(e2.right().value()); } }; } }); } /** * An equal instance for the {@link Validation} type. * * @param ea Equality across the failing side of {@link Validation}. * @param eb Equality across the succeeding side of {@link Validation}. * @return An equal instance for the {@link Validation} type. */ public static <A, B> Equal<Validation<A, B>> validationEqual(final Equal<A> ea, final Equal<B> eb) { return eitherEqual(ea, eb).comap(Validation.<A, B>either()); } /** * An equal instance for the {@link List} type. * * @param ea Equality across the elements of the list. * @return An equal instance for the {@link List} type. */ public static <A> Equal<List<A>> listEqual(final Equal<A> ea) { return new Equal<List<A>>(new F<List<A>, F<List<A>, Boolean>>() { public F<List<A>, Boolean> f(final List<A> a1) { return new F<List<A>, Boolean>() { public Boolean f(final List<A> a2) { List<A> x1 = a1; List<A> x2 = a2; while (x1.isNotEmpty() && x2.isNotEmpty()) { if (!ea.eq(x1.head(), x2.head())) return false; x1 = x1.tail(); x2 = x2.tail(); } return x1.isEmpty() && x2.isEmpty(); } }; } }); } /** * An equal instance for the {@link NonEmptyList} type. * * @param ea Equality across the elements of the non-empty list. * @return An equal instance for the {@link NonEmptyList} type. */ public static <A> Equal<NonEmptyList<A>> nonEmptyListEqual(final Equal<A> ea) { return listEqual(ea).comap(NonEmptyList.<A>toList_()); } /** * An equal instance for the {@link Option} type. * * @param ea Equality across the element of the option. * @return An equal instance for the {@link Option} type. */ public static <A> Equal<Option<A>> optionEqual(final Equal<A> ea) { return new Equal<Option<A>>(new F<Option<A>, F<Option<A>, Boolean>>() { public F<Option<A>, Boolean> f(final Option<A> o1) { return new F<Option<A>, Boolean>() { public Boolean f(final Option<A> o2) { return o1.isNone() && o2.isNone() || o1.isSome() && o2.isSome() && ea.f.f(o1.some()).f(o2.some()); } }; } }); } /** * An equal instance for the {@link Stream} type. * * @param ea Equality across the elements of the stream. * @return An equal instance for the {@link Stream} type. */ public static <A> Equal<Stream<A>> streamEqual(final Equal<A> ea) { return new Equal<Stream<A>>(new F<Stream<A>, F<Stream<A>, Boolean>>() { public F<Stream<A>, Boolean> f(final Stream<A> a1) { return new F<Stream<A>, Boolean>() { public Boolean f(final Stream<A> a2) { Stream<A> x1 = a1; Stream<A> x2 = a2; while (x1.isNotEmpty() && x2.isNotEmpty()) { if (!ea.eq(x1.head(), x2.head())) return false; x1 = x1.tail()._1(); x2 = x2.tail()._1(); } return x1.isEmpty() && x2.isEmpty(); } }; } }); } /** * An equal instance for the {@link Array} type. * * @param ea Equality across the elements of the array. * @return An equal instance for the {@link Array} type. */ public static <A> Equal<Array<A>> arrayEqual(final Equal<A> ea) { return new Equal<Array<A>>(new F<Array<A>, F<Array<A>, Boolean>>() { public F<Array<A>, Boolean> f(final Array<A> a1) { return new F<Array<A>, Boolean>() { public Boolean f(final Array<A> a2) { if (a1.length() == a2.length()) { for (int i = 0; i < a1.length(); i++) { if (!ea.eq(a1.get(i), a2.get(i))) return false; } return true; } else return false; } }; } }); } /** * An equal instance for the {@link Tree} type. * * @param ea Equality across the elements of the tree. * @return An equal instance for the {@link Tree} type. */ public static <A> Equal<Tree<A>> treeEqual(final Equal<A> ea) { return new Equal<Tree<A>>(curry(new F2<Tree<A>, Tree<A>, Boolean>() { public Boolean f(final Tree<A> t1, final Tree<A> t2) { return ea.eq(t1.root(), t2.root()) && p1Equal(streamEqual(treeEqual(ea))).eq(t2.subForest(), t1.subForest()); } })); } /** * An equal instance for a product-1. * * @param ea Equality across the first element of the product. * @return An equal instance for a product-1. */ public static <A> Equal<P1<A>> p1Equal(final Equal<A> ea) { return new Equal<P1<A>>(new F<P1<A>, F<P1<A>, Boolean>>() { public F<P1<A>, Boolean> f(final P1<A> p1) { return new F<P1<A>, Boolean>() { public Boolean f(final P1<A> p2) { return ea.eq(p1._1(), p2._1()); } }; } }); } /** * An equal instance for a product-2. * * @param ea Equality across the first element of the product. * @param eb Equality across the second element of the product. * @return An equal instance for a product-2. */ public static <A, B> Equal<P2<A, B>> p2Equal(final Equal<A> ea, final Equal<B> eb) { return new Equal<P2<A, B>>(new F<P2<A, B>, F<P2<A, B>, Boolean>>() { public F<P2<A, B>, Boolean> f(final P2<A, B> p1) { return new F<P2<A, B>, Boolean>() { public Boolean f(final P2<A, B> p2) { return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()); } }; } }); } /** * An equal instance for a product-3. * * @param ea Equality across the first element of the product. * @param eb Equality across the second element of the product. * @param ec Equality across the third element of the product. * @return An equal instance for a product-3. */ public static <A, B, C> Equal<P3<A, B, C>> p3Equal(final Equal<A> ea, final Equal<B> eb, final Equal<C> ec) { return new Equal<P3<A, B, C>>(new F<P3<A, B, C>, F<P3<A, B, C>, Boolean>>() { public F<P3<A, B, C>, Boolean> f(final P3<A, B, C> p1) { return new F<P3<A, B, C>, Boolean>() { public Boolean f(final P3<A, B, C> p2) { return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()); } }; } }); } /** * An equal instance for a product-4. * * @param ea Equality across the first element of the product. * @param eb Equality across the second element of the product. * @param ec Equality across the third element of the product. * @param ed Equality across the fourth element of the product. * @return An equal instance for a product-4. */ public static <A, B, C, D> Equal<P4<A, B, C, D>> p4Equal(final Equal<A> ea, final Equal<B> eb, final Equal<C> ec, final Equal<D> ed) { return new Equal<P4<A, B, C, D>>(new F<P4<A, B, C, D>, F<P4<A, B, C, D>, Boolean>>() { public F<P4<A, B, C, D>, Boolean> f(final P4<A, B, C, D> p1) { return new F<P4<A, B, C, D>, Boolean>() { public Boolean f(final P4<A, B, C, D> p2) { return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) && ed.eq(p1._4(), p2._4()); } }; } }); } /** * An equal instance for a product-5. * * @param ea Equality across the first element of the product. * @param eb Equality across the second element of the product. * @param ec Equality across the third element of the product. * @param ed Equality across the fourth element of the product. * @param ee Equality across the fifth element of the product. * @return An equal instance for a product-5. */ public static <A, B, C, D, E> Equal<P5<A, B, C, D, E>> p5Equal(final Equal<A> ea, final Equal<B> eb, final Equal<C> ec, final Equal<D> ed, final Equal<E> ee) { return new Equal<P5<A, B, C, D, E>>(new F<P5<A, B, C, D, E>, F<P5<A, B, C, D, E>, Boolean>>() { public F<P5<A, B, C, D, E>, Boolean> f(final P5<A, B, C, D, E> p1) { return new F<P5<A, B, C, D, E>, Boolean>() { public Boolean f(final P5<A, B, C, D, E> p2) { return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) && ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()); } }; } }); } /** * An equal instance for a product-6. * * @param ea Equality across the first element of the product. * @param eb Equality across the second element of the product. * @param ec Equality across the third element of the product. * @param ed Equality across the fourth element of the product. * @param ee Equality across the fifth element of the product. * @param ef Equality across the sixth element of the product. * @return An equal instance for a product-6. */ public static <A, B, C, D, E, F$> Equal<P6<A, B, C, D, E, F$>> p6Equal(final Equal<A> ea, final Equal<B> eb, final Equal<C> ec, final Equal<D> ed, final Equal<E> ee, final Equal<F$> ef) { return new Equal<P6<A, B, C, D, E, F$>>(new F<P6<A, B, C, D, E, F$>, F<P6<A, B, C, D, E, F$>, Boolean>>() { public F<P6<A, B, C, D, E, F$>, Boolean> f(final P6<A, B, C, D, E, F$> p1) { return new F<P6<A, B, C, D, E, F$>, Boolean>() { public Boolean f(final P6<A, B, C, D, E, F$> p2) { return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) && ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()) && ef.eq(p1._6(), p2._6()); } }; } }); } /** * An equal instance for a product-7. * * @param ea Equality across the first element of the product. * @param eb Equality across the second element of the product. * @param ec Equality across the third element of the product. * @param ed Equality across the fourth element of the product. * @param ee Equality across the fifth element of the product. * @param ef Equality across the sixth element of the product. * @param eg Equality across the seventh element of the product. * @return An equal instance for a product-7. */ public static <A, B, C, D, E, F$, G> Equal<P7<A, B, C, D, E, F$, G>> p7Equal(final Equal<A> ea, final Equal<B> eb, final Equal<C> ec, final Equal<D> ed, final Equal<E> ee, final Equal<F$> ef, final Equal<G> eg) { return new Equal<P7<A, B, C, D, E, F$, G>>(new F<P7<A, B, C, D, E, F$, G>, F<P7<A, B, C, D, E, F$, G>, Boolean>>() { public F<P7<A, B, C, D, E, F$, G>, Boolean> f(final P7<A, B, C, D, E, F$, G> p1) { return new F<P7<A, B, C, D, E, F$, G>, Boolean>() { public Boolean f(final P7<A, B, C, D, E, F$, G> p2) { return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) && ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()) && ef.eq(p1._6(), p2._6()) && eg.eq(p1._7(), p2._7()); } }; } }); } /** * An equal instance for a product-8. * * @param ea Equality across the first element of the product. * @param eb Equality across the second element of the product. * @param ec Equality across the third element of the product. * @param ed Equality across the fourth element of the product. * @param ee Equality across the fifth element of the product. * @param ef Equality across the sixth element of the product. * @param eg Equality across the seventh element of the product. * @param eh Equality across the eighth element of the product. * @return An equal instance for a product-8. */ public static <A, B, C, D, E, F$, G, H> Equal<P8<A, B, C, D, E, F$, G, H>> p8Equal(final Equal<A> ea, final Equal<B> eb, final Equal<C> ec, final Equal<D> ed, final Equal<E> ee, final Equal<F$> ef, final Equal<G> eg, final Equal<H> eh) { return new Equal<P8<A, B, C, D, E, F$, G, H>>( new F<P8<A, B, C, D, E, F$, G, H>, F<P8<A, B, C, D, E, F$, G, H>, Boolean>>() { public F<P8<A, B, C, D, E, F$, G, H>, Boolean> f(final P8<A, B, C, D, E, F$, G, H> p1) { return new F<P8<A, B, C, D, E, F$, G, H>, Boolean>() { public Boolean f(final P8<A, B, C, D, E, F$, G, H> p2) { return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) && ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()) && ef.eq(p1._6(), p2._6()) && eg.eq(p1._7(), p2._7()) && eh.eq(p1._8(), p2._8()); } }; } }); } /** * An equal instance for a vector-2. * * @param ea Equality across the elements of the vector. * @return An equal instance for a vector-2. */ public static <A> Equal<V2<A>> v2Equal(final Equal<A> ea) { return streamEqual(ea).comap(V2.<A>toStream_()); } /** * An equal instance for a vector-3. * * @param ea Equality across the elements of the vector. * @return An equal instance for a vector-3. */ public static <A> Equal<V3<A>> v3Equal(final Equal<A> ea) { return streamEqual(ea).comap(V3.<A>toStream_()); } /** * An equal instance for a vector-4. * * @param ea Equality across the elements of the vector. * @return An equal instance for a vector-4. */ public static <A> Equal<V4<A>> v4Equal(final Equal<A> ea) { return streamEqual(ea).comap(V4.<A>toStream_()); } /** * An equal instance for a vector-5. * * @param ea Equality across the elements of the vector. * @return An equal instance for a vector-5. */ public static <A> Equal<V5<A>> v5Equal(final Equal<A> ea) { return streamEqual(ea).comap(V5.<A>toStream_()); } /** * An equal instance for a vector-6. * * @param ea Equality across the elements of the vector. * @return An equal instance for a vector-6. */ public static <A> Equal<V6<A>> v6Equal(final Equal<A> ea) { return streamEqual(ea).comap(V6.<A>toStream_()); } /** * An equal instance for a vector-7. * * @param ea Equality across the elements of the vector. * @return An equal instance for a vector-7. */ public static <A> Equal<V7<A>> v7Equal(final Equal<A> ea) { return streamEqual(ea).comap(V7.<A>toStream_()); } /** * An equal instance for a vector-8. * * @param ea Equality across the elements of the vector. * @return An equal instance for a vector-8. */ public static <A> Equal<V8<A>> v8Equal(final Equal<A> ea) { return streamEqual(ea).comap(V8.<A>toStream_()); } /** * An equal instance for lazy strings. */ public static final Equal<LazyString> eq = streamEqual(charEqual).comap(LazyString.toStream); /** * An equal instance for the empty heterogeneous list. */ public static final Equal<HList.HNil> hListEqual = anyEqual(); /** * An equal instance for heterogeneous lists. * * @param e Equality for the first element of the list. * @param l Equality for the rest of the list. * @return an equal instance for a heterogeneous list. */ public static <E, L extends HList<L>> Equal<HList.HCons<E, L>> hListEqual(final Equal<E> e, final Equal<L> l) { return equal(curry(new F2<HList.HCons<E, L>, HList.HCons<E, L>, Boolean>() { public Boolean f(final HList.HCons<E, L> c1, final HList.HCons<E, L> c2) { return e.eq(c1.head(), c2.head()) && l.eq(c1.tail(), c2.tail()); } })); } /** * Equal instance for sets. * * @param e Equality for the set elements. * @return An equal instance for sets. */ public static <A> Equal<Set<A>> setEqual(final Equal<A> e) { return equal(curry(new F2<Set<A>, Set<A>, Boolean>() { public Boolean f(final Set<A> a, final Set<A> b) { return streamEqual(e).eq(a.toStream(), b.toStream()); } })); } public static <A, B> Equal<Writer<A, B>> writerEqual(Equal<A> eq1, Equal<B> eq2) { return new Equal<Writer<A, B>>(w1 -> w2 -> Equal.p2Equal(eq1, eq2).eq(w1.run(), w2.run())); } }