Skip to content

Commit 25d10ea

Browse files
committed
Initial implementation of optimizable definitions for Equal
1 parent 7c2605e commit 25d10ea

File tree

1 file changed

+130
-37
lines changed

1 file changed

+130
-37
lines changed

core/src/main/java/fj/Equal.java

Lines changed: 130 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
package fj;
22

3-
import static fj.Function.curry;
4-
5-
import fj.data.*;
3+
import fj.data.Array;
4+
import fj.data.Either;
5+
import fj.data.LazyString;
6+
import fj.data.List;
7+
import fj.data.Natural;
8+
import fj.data.NonEmptyList;
9+
import fj.data.Option;
10+
import fj.data.Seq;
11+
import fj.data.Set;
12+
import fj.data.Stream;
13+
import fj.data.Tree;
14+
import fj.data.TreeMap;
15+
import fj.data.Validation;
16+
import fj.data.Writer;
617
import fj.data.hlist.HList;
718
import fj.data.vector.V2;
819
import fj.data.vector.V3;
@@ -12,19 +23,50 @@
1223
import fj.data.vector.V7;
1324
import fj.data.vector.V8;
1425

15-
import java.math.BigInteger;
1626
import java.math.BigDecimal;
27+
import java.math.BigInteger;
28+
29+
import static fj.Function.compose;
30+
import static fj.Function.constant;
31+
import static fj.Function.curry;
1732

1833
/**
1934
* Tests for equality between two objects.
2035
*
2136
* @version %build.number%
2237
*/
2338
public final class Equal<A> {
24-
private final F<A, F<A, Boolean>> f;
2539

26-
private Equal(final F<A, F<A, Boolean>> f) {
27-
this.f = f;
40+
/**
41+
* Primitives functions of Equal: minimal definition and overridable methods.
42+
*/
43+
interface Definition<A> {
44+
45+
F<A, Boolean> equal(A a);
46+
47+
default boolean equal(A a1, A a2) {
48+
return equal(a1).f(a2);
49+
}
50+
}
51+
52+
/**
53+
* Primitives functions of Equal: alternative minimal definition and overridable methods.
54+
*/
55+
interface AlternateDefinition<A> extends Definition<A> {
56+
57+
@Override
58+
default F<A, Boolean> equal(A a) {
59+
return a2 -> equal(a, a2);
60+
}
61+
62+
@Override
63+
boolean equal(A a1, A a2);
64+
}
65+
66+
private final Definition<A> def;
67+
68+
private Equal(final Definition<A> def) {
69+
this.def = def;
2870
}
2971

3072
/**
@@ -35,7 +77,7 @@ private Equal(final F<A, F<A, Boolean>> f) {
3577
* @return <code>true</code> if the two given arguments are equal, <code>false</code> otherwise.
3678
*/
3779
public boolean eq(final A a1, final A a2) {
38-
return f.f(a1).f(a2);
80+
return def.equal(a1, a2);
3981
}
4082

4183
/**
@@ -46,7 +88,7 @@ public boolean eq(final A a1, final A a2) {
4688
* @return <code>true</code> if the two given arguments are not equal, <code>false</code> otherwise.
4789
*/
4890
public boolean notEq(final A a1, final A a2) {
49-
return !eq(a1, a2);
91+
return !def.equal(a1, a2);
5092
}
5193

5294
/**
@@ -55,7 +97,7 @@ public boolean notEq(final A a1, final A a2) {
5597
* @return A function that returns <code>true</code> if the two given arguments are equal.
5698
*/
5799
public F2<A, A, Boolean> eq() {
58-
return this::eq;
100+
return def::equal;
59101
}
60102

61103
/**
@@ -65,7 +107,7 @@ public F2<A, A, Boolean> eq() {
65107
* @return A function that returns <code>true</code> if the given argument equals the argument to this method.
66108
*/
67109
public F<A, Boolean> eq(final A a) {
68-
return f.f(a);
110+
return def.equal(a);
69111
}
70112

71113
/**
@@ -75,7 +117,18 @@ public F<A, Boolean> eq(final A a) {
75117
* @return A new equal.
76118
*/
77119
public <B> Equal<B> contramap(final F<B, A> f) {
78-
return equal(F1Functions.o(F1Functions.o(F1Functions.andThen(f), this.f), f));
120+
Definition<A> eaDef = def;
121+
return equalDef(new Definition<B>(){
122+
@Override
123+
public F<B, Boolean> equal(B b) {
124+
return compose(eaDef.equal(f.f(b)), f);
125+
}
126+
127+
@Override
128+
public boolean equal(B b1, B b2) {
129+
return eaDef.equal(f.f(b1), f.f(b2));
130+
}
131+
});
79132
}
80133

81134
/**
@@ -85,7 +138,27 @@ public <B> Equal<B> contramap(final F<B, A> f) {
85138
* @return An equal instance from the given function.
86139
*/
87140
public static <A> Equal<A> equal(final F<A, F<A, Boolean>> f) {
88-
return new Equal<>(f);
141+
return new Equal<>(f::f);
142+
}
143+
144+
/**
145+
* Constructs an equal instance from the given definition.
146+
*
147+
* @param definition The minimal definition of the equal instance.
148+
* @return An equal instance from the given function.
149+
*/
150+
public static <A> Equal<A> equalDef(final Definition<A> definition) {
151+
return new Equal<>(definition);
152+
}
153+
154+
/**
155+
* Constructs an equal instance from the given definition.
156+
*
157+
* @param definition The minimal definition of the equal instance.
158+
* @return An equal instance from the given function.
159+
*/
160+
public static <A> Equal<A> equalAltDef(final AlternateDefinition<A> definition) {
161+
return new Equal<>(definition);
89162
}
90163

91164
/**
@@ -96,7 +169,17 @@ public static <A> Equal<A> equal(final F<A, F<A, Boolean>> f) {
96169
* equality.
97170
*/
98171
public static <A> Equal<A> anyEqual() {
99-
return equal(a1 -> a1::equals);
172+
return equalDef(new Definition<A>() {
173+
@Override
174+
public F<A, Boolean> equal(A a) {
175+
return a::equals;
176+
}
177+
178+
@Override
179+
public boolean equal(A a1, A a2) {
180+
return a1.equals(a2);
181+
}
182+
});
100183
}
101184

102185
/**
@@ -163,7 +246,7 @@ public static <A> Equal<A> anyEqual() {
163246
* An equal instance for the {@link StringBuffer} type.
164247
*/
165248
public static final Equal<StringBuffer> stringBufferEqual =
166-
equal(sb1 -> sb2 -> {
249+
equalAltDef((sb1, sb2) -> {
167250
if (sb1.length() == sb2.length()) {
168251
for (int i = 0; i < sb1.length(); i++)
169252
if (sb1.charAt(i) != sb2.charAt(i))
@@ -177,7 +260,7 @@ public static <A> Equal<A> anyEqual() {
177260
* An equal instance for the {@link StringBuilder} type.
178261
*/
179262
public static final Equal<StringBuilder> stringBuilderEqual =
180-
equal(sb1 -> sb2 -> {
263+
equalAltDef((sb1, sb2) -> {
181264
if (sb1.length() == sb2.length()) {
182265
for (int i = 0; i < sb1.length(); i++)
183266
if (sb1.charAt(i) != sb2.charAt(i))
@@ -195,8 +278,12 @@ public static <A> Equal<A> anyEqual() {
195278
* @return An equal instance for the {@link Either} type.
196279
*/
197280
public static <A, B> Equal<Either<A, B>> eitherEqual(final Equal<A> ea, final Equal<B> eb) {
198-
return equal(e1 -> e2 -> e1.isLeft() && e2.isLeft() && ea.f.f(e1.left().value()).f(e2.left().value()) ||
199-
e1.isRight() && e2.isRight() && eb.f.f(e1.right().value()).f(e2.right().value()));
281+
Definition<A> eaDef = ea.def;
282+
Definition<B> ebDef = eb.def;
283+
return equalDef(e1 -> e1.either(
284+
a1 -> Either.cata(eaDef.equal(a1), (B __) -> false),
285+
b1 -> Either.cata((A __)-> false, ebDef.equal(b1))
286+
));
200287
}
201288

202289
/**
@@ -217,12 +304,13 @@ public static <A, B> Equal<Validation<A, B>> validationEqual(final Equal<A> ea,
217304
* @return An equal instance for the {@link List} type.
218305
*/
219306
public static <A> Equal<List<A>> listEqual(final Equal<A> ea) {
220-
return equal(a1 -> a2 -> {
307+
Definition<A> eaDef = ea.def;
308+
return equalAltDef((a1, a2) -> {
221309
List<A> x1 = a1;
222310
List<A> x2 = a2;
223311

224312
while (x1.isNotEmpty() && x2.isNotEmpty()) {
225-
if (!ea.eq(x1.head(), x2.head()))
313+
if (!eaDef.equal(x1.head(), x2.head()))
226314
return false;
227315

228316
x1 = x1.tail();
@@ -250,12 +338,15 @@ public static <A> Equal<NonEmptyList<A>> nonEmptyListEqual(final Equal<A> ea) {
250338
* @return An equal instance for the {@link Option} type.
251339
*/
252340
public static <A> Equal<Option<A>> optionEqual(final Equal<A> ea) {
253-
return equal(o1 -> o2 -> o1.isNone() && o2.isNone() ||
254-
o1.isSome() && o2.isSome() && ea.f.f(o1.some()).f(o2.some()));
341+
Definition<A> eaDef = ea.def;
342+
return equalDef(o1 -> o1.option(
343+
Option.isNone_(),
344+
a1 -> Option.cata(false, eaDef.equal(a1))
345+
));
255346
}
256347

257348
public static <A> Equal<Seq<A>> seqEqual(final Equal<A> e) {
258-
return equal(s1 -> s2 -> streamEqual(e).eq(s1.toStream(), s2.toStream()));
349+
return streamEqual(e).contramap(Seq::toStream);
259350
}
260351

261352
/**
@@ -265,12 +356,13 @@ public static <A> Equal<Seq<A>> seqEqual(final Equal<A> e) {
265356
* @return An equal instance for the {@link Stream} type.
266357
*/
267358
public static <A> Equal<Stream<A>> streamEqual(final Equal<A> ea) {
268-
return equal(a1 -> a2 -> {
359+
Definition<A> eaDef = ea.def;
360+
return equalAltDef((a1, a2) -> {
269361
Stream<A> x1 = a1;
270362
Stream<A> x2 = a2;
271363

272364
while (x1.isNotEmpty() && x2.isNotEmpty()) {
273-
if (!ea.eq(x1.head(), x2.head()))
365+
if (!eaDef.equal(x1.head(), x2.head()))
274366
return false;
275367

276368
x1 = x1.tail()._1();
@@ -288,10 +380,11 @@ public static <A> Equal<Stream<A>> streamEqual(final Equal<A> ea) {
288380
* @return An equal instance for the {@link Array} type.
289381
*/
290382
public static <A> Equal<Array<A>> arrayEqual(final Equal<A> ea) {
291-
return equal(a1 -> a2 -> {
383+
Definition<A> eaDef = ea.def;
384+
return equalAltDef((a1, a2) -> {
292385
if (a1.length() == a2.length()) {
293386
for (int i = 0; i < a1.length(); i++) {
294-
if (!ea.eq(a1.get(i), a2.get(i)))
387+
if (!eaDef.equal(a1.get(i), a2.get(i)))
295388
return false;
296389
}
297390
return true;
@@ -307,7 +400,7 @@ public static <A> Equal<Array<A>> arrayEqual(final Equal<A> ea) {
307400
* @return An equal instance for the {@link Tree} type.
308401
*/
309402
public static <A> Equal<Tree<A>> treeEqual(final Equal<A> ea) {
310-
return Equal.equal(curry((t1, t2) -> ea.eq(t1.root(), t2.root()) && p1Equal(streamEqual(Equal.treeEqual(ea))).eq(t2.subForest(), t1.subForest())));
403+
return equalAltDef((t1, t2) -> ea.eq(t1.root(), t2.root()) && p1Equal(streamEqual(treeEqual(ea))).eq(t2.subForest(), t1.subForest()));
311404
}
312405

313406
/**
@@ -317,7 +410,7 @@ public static <A> Equal<Tree<A>> treeEqual(final Equal<A> ea) {
317410
* @return An equal instance for a product-1.
318411
*/
319412
public static <A> Equal<P1<A>> p1Equal(final Equal<A> ea) {
320-
return equal(p1 -> p2 -> ea.eq(p1._1(), p2._1()));
413+
return equalAltDef((p1, p2) -> ea.eq(p1._1(), p2._1()));
321414
}
322415

323416
/**
@@ -328,7 +421,7 @@ public static <A> Equal<P1<A>> p1Equal(final Equal<A> ea) {
328421
* @return An equal instance for a product-2.
329422
*/
330423
public static <A, B> Equal<P2<A, B>> p2Equal(final Equal<A> ea, final Equal<B> eb) {
331-
return equal(p1 -> p2 -> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()));
424+
return equalAltDef((p1, p2)-> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()));
332425
}
333426

334427
/**
@@ -340,7 +433,7 @@ public static <A, B> Equal<P2<A, B>> p2Equal(final Equal<A> ea, final Equal<B> e
340433
* @return An equal instance for a product-3.
341434
*/
342435
public static <A, B, C> Equal<P3<A, B, C>> p3Equal(final Equal<A> ea, final Equal<B> eb, final Equal<C> ec) {
343-
return equal(p1 -> p2 -> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()));
436+
return equalAltDef((p1, p2) -> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()));
344437
}
345438

346439
/**
@@ -354,7 +447,7 @@ public static <A, B, C> Equal<P3<A, B, C>> p3Equal(final Equal<A> ea, final Equa
354447
*/
355448
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,
356449
final Equal<D> ed) {
357-
return equal(p1 -> p2 -> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
450+
return equalAltDef((p1, p2) -> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
358451
ed.eq(p1._4(), p2._4()));
359452
}
360453

@@ -371,7 +464,7 @@ public static <A, B, C, D> Equal<P4<A, B, C, D>> p4Equal(final Equal<A> ea, fina
371464
public static <A, B, C, D, E> Equal<P5<A, B, C, D, E>> p5Equal(final Equal<A> ea, final Equal<B> eb,
372465
final Equal<C> ec, final Equal<D> ed,
373466
final Equal<E> ee) {
374-
return equal(p1 -> p2 -> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
467+
return equalAltDef((p1, p2) -> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
375468
ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()));
376469
}
377470

@@ -389,7 +482,7 @@ public static <A, B, C, D, E> Equal<P5<A, B, C, D, E>> p5Equal(final Equal<A> ea
389482
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,
390483
final Equal<C> ec, final Equal<D> ed,
391484
final Equal<E> ee, final Equal<F$> ef) {
392-
return equal(p1 -> p2 -> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
485+
return equalAltDef((p1, p2) -> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
393486
ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()) && ef.eq(p1._6(), p2._6()));
394487
}
395488

@@ -409,7 +502,7 @@ public static <A, B, C, D, E> Equal<P5<A, B, C, D, E>> p5Equal(final Equal<A> ea
409502
final Equal<C> ec, final Equal<D> ed,
410503
final Equal<E> ee, final Equal<F$> ef,
411504
final Equal<G> eg) {
412-
return equal(p1 -> p2 -> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
505+
return equalAltDef((p1, p2) -> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
413506
ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()) && ef.eq(p1._6(), p2._6()) &&
414507
eg.eq(p1._7(), p2._7()));
415508
}
@@ -435,8 +528,8 @@ public static <A, B, C, D, E> Equal<P5<A, B, C, D, E>> p5Equal(final Equal<A> ea
435528
final Equal<F$> ef,
436529
final Equal<G> eg,
437530
final Equal<H> eh) {
438-
return equal(
439-
p1 -> p2 -> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
531+
return equalAltDef(
532+
(p1, p2) -> ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
440533
ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()) && ef.eq(p1._6(), p2._6()) &&
441534
eg.eq(p1._7(), p2._7()) && eh.eq(p1._8(), p2._8()));
442535
}

0 commit comments

Comments
 (0)