Skip to content

Commit 1c94e08

Browse files
committed
Initial refactoring of Ord to use Definition interface
1 parent 2aa3878 commit 1c94e08

File tree

1 file changed

+126
-40
lines changed

1 file changed

+126
-40
lines changed

core/src/main/java/fj/Ord.java

Lines changed: 126 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import static fj.Function.apply;
1818
import static fj.Function.compose;
19+
import static fj.Function.compose2;
1920
import static fj.Function.curry;
2021
import static fj.Semigroup.semigroup;
2122

@@ -25,12 +26,49 @@
2526
* @version %build.number%
2627
*/
2728
public final class Ord<A> {
28-
private final F<A, F<A, Ordering>> f;
2929

30-
private Ord(final F<A, F<A, Ordering>> f) {
31-
this.f = f;
32-
this.max = a1 -> apply((a2, o) -> o == Ordering.GT ? a1 : a2, f.f(a1));
33-
this.min = a1 -> apply((a2, o) -> o == Ordering.LT ? a1 : a2, f.f(a1));
30+
/**
31+
* Primitives functions of Ord: minimal definition and overridable methods.
32+
*/
33+
public interface Definition<A> extends Equal.Definition<A> {
34+
35+
F<A, Ordering> compare(A a);
36+
37+
default Ordering compare(A a1, A a2) {
38+
return compare(a1).f(a2);
39+
}
40+
41+
@Override
42+
default boolean equal(A a1, A a2) {
43+
return compare(a1, a2) == Ordering.EQ;
44+
}
45+
46+
@Override
47+
default F<A, Boolean> equal(A a) {
48+
return compose(o -> o == Ordering.EQ, compare(a));
49+
}
50+
}
51+
52+
/**
53+
* Primitives functions of Ord: alternative minimal definition and overridable methods.
54+
*/
55+
public interface AlternateDefinition<A> extends Definition<A> {
56+
57+
Ordering compare(A a1, A a2);
58+
59+
default F<A, Ordering> compare(A a1) {
60+
return a2 -> compare(a1, a2);
61+
}
62+
63+
}
64+
65+
66+
private final Definition<A> def;
67+
68+
private Ord(final Definition<A> def) {
69+
this.def = def;
70+
this.max = a1 -> apply((a2, o) -> o == Ordering.GT ? a1 : a2, def.compare(a1));
71+
this.min = a1 -> apply((a2, o) -> o == Ordering.LT ? a1 : a2, def.compare(a1));
3472
}
3573

3674
/**
@@ -39,7 +77,7 @@ private Ord(final F<A, F<A, Ordering>> f) {
3977
* @return A function that returns an ordering for its arguments.
4078
*/
4179
public F<A, F<A, Ordering>> compare() {
42-
return f;
80+
return def::compare;
4381
}
4482

4583
/**
@@ -50,7 +88,7 @@ public F<A, F<A, Ordering>> compare() {
5088
* @return An ordering for the given arguments.
5189
*/
5290
public Ordering compare(final A a1, final A a2) {
53-
return f.f(a1).f(a2);
91+
return def.compare(a1, a2);
5492
}
5593

5694
/**
@@ -61,7 +99,7 @@ public Ordering compare(final A a1, final A a2) {
6199
* @return <code>true</code> if the given arguments are equal, <code>false</code> otherwise.
62100
*/
63101
public boolean eq(final A a1, final A a2) {
64-
return compare(a1, a2) == Ordering.EQ;
102+
return def.compare(a1, a2) == Ordering.EQ;
65103
}
66104

67105
/**
@@ -70,7 +108,7 @@ public boolean eq(final A a1, final A a2) {
70108
* @return An <code>Equal</code> for this order.
71109
*/
72110
public Equal<A> equal() {
73-
return Equal.equal(a -> compose(o -> o == Ordering.EQ, f.f(a)));
111+
return Equal.equalDef(def);
74112
}
75113

76114
/**
@@ -80,7 +118,18 @@ public Equal<A> equal() {
80118
* @return A new ord.
81119
*/
82120
public <B> Ord<B> contramap(final F<B, A> f) {
83-
return ord(F1Functions.o(F1Functions.o(F1Functions.andThen(f), this.f), f));
121+
Definition<A> selfDef = def;
122+
return ordDef(new Definition<B>() {
123+
@Override
124+
public F<B, Ordering> compare(B b) {
125+
return compose(selfDef.compare(f.f(b)), f);
126+
}
127+
128+
@Override
129+
public Ordering compare(B b1, B b2) {
130+
return selfDef.compare(f.f(b1), f.f(b2));
131+
}
132+
});
84133
}
85134

86135
/**
@@ -93,7 +142,7 @@ public <B> Ord<B> contramap(final F<B, A> f) {
93142
* <code>false</code> otherwise.
94143
*/
95144
public boolean isLessThan(final A a1, final A a2) {
96-
return compare(a1, a2) == Ordering.LT;
145+
return def.compare(a1, a2) == Ordering.LT;
97146
}
98147

99148
/**
@@ -106,7 +155,7 @@ public boolean isLessThan(final A a1, final A a2) {
106155
* <code>false</code> otherwise.
107156
*/
108157
public boolean isLessThanOrEqualTo(final A a1, final A a2) {
109-
return compare(a1, a2) != Ordering.GT;
158+
return def.compare(a1, a2) != Ordering.GT;
110159
}
111160

112161
/**
@@ -119,7 +168,7 @@ public boolean isLessThanOrEqualTo(final A a1, final A a2) {
119168
* argument, <code>false</code> otherwise.
120169
*/
121170
public boolean isGreaterThan(final A a1, final A a2) {
122-
return compare(a1, a2) == Ordering.GT;
171+
return def.compare(a1, a2) == Ordering.GT;
123172
}
124173

125174
/**
@@ -129,7 +178,7 @@ public boolean isGreaterThan(final A a1, final A a2) {
129178
* @return A function that returns true if its argument is less than the argument to this method.
130179
*/
131180
public F<A, Boolean> isLessThan(final A a) {
132-
return compose(o -> o != Ordering.LT, f.f(a));
181+
return compose(o -> o != Ordering.LT, def.compare(a));
133182
}
134183

135184
/**
@@ -139,7 +188,7 @@ public F<A, Boolean> isLessThan(final A a) {
139188
* @return A function that returns true if its argument is greater than the argument to this method.
140189
*/
141190
public F<A, Boolean> isGreaterThan(final A a) {
142-
return compose(o -> o != Ordering.GT, f.f(a));
191+
return compose(o -> o != Ordering.GT, def.compare(a));
143192
}
144193

145194
/**
@@ -183,7 +232,20 @@ public final Semigroup<A> maxSemigroup() {
183232
return semigroup(max);
184233
}
185234

186-
public final Ord<A> reverse() { return ord(Function.flip(f)); }
235+
public final Ord<A> reverse() {
236+
Definition<A> selfDef = def;
237+
return ordDef(new Definition<A>() {
238+
@Override
239+
public F<A, Ordering> compare(A a) {
240+
return compose(Ordering::reverse, selfDef.compare(a));
241+
}
242+
243+
@Override
244+
public Ordering compare(A a1, A a2) {
245+
return selfDef.compare(a2, a1);
246+
}
247+
});
248+
}
187249

188250
/**
189251
* Returns an order instance that uses the given equality test and ordering function.
@@ -192,9 +254,30 @@ public final Semigroup<A> maxSemigroup() {
192254
* @return An order instance.
193255
*/
194256
public static <A> Ord<A> ord(final F<A, F<A, Ordering>> f) {
195-
return new Ord<>(f);
257+
return new Ord<>(f::f);
196258
}
197259

260+
/**
261+
* Returns an order instance that uses the given minimal equality test and ordering definiion.
262+
*
263+
* @param def The order definition.
264+
* @return An order instance.
265+
*/
266+
public static <A> Ord<A> ordDef(final Definition<A> def) {
267+
return new Ord<>(def);
268+
}
269+
270+
/**
271+
* Returns an order instance that uses the given minimal equality test and ordering definiion.
272+
*
273+
* @param def The order definition.
274+
* @return An order instance.
275+
*/
276+
public static <A> Ord<A> ordDef(final AlternateDefinition<A> def) {
277+
return new Ord<>(def);
278+
}
279+
280+
198281
/**
199282
* An order instance for the <code>boolean</code> type.
200283
*/
@@ -248,15 +331,15 @@ public static <A> Ord<A> ord(final F<A, F<A, Ordering>> f) {
248331
/**
249332
* An order instance for the {@link Ordering} type.
250333
*/
251-
public static final Ord<Ordering> orderingOrd = Ord.ord(curry((o1, o2) -> o1 == o2 ?
334+
public static final Ord<Ordering> orderingOrd = ordDef((o1, o2) -> o1 == o2 ?
252335
Ordering.EQ :
253336
o1 == Ordering.LT ?
254337
Ordering.LT :
255338
o2 == Ordering.LT ?
256339
Ordering.GT :
257340
o1 == Ordering.EQ ?
258341
Ordering.LT :
259-
Ordering.GT));
342+
Ordering.GT);
260343

261344
/**
262345
* An order instance for the {@link String} type.
@@ -280,13 +363,14 @@ public static <A> Ord<A> ord(final F<A, F<A, Ordering>> f) {
280363
* @return An order instance for the {@link Option} type.
281364
*/
282365
public static <A> Ord<Option<A>> optionOrd(final Ord<A> oa) {
283-
return ord(o1 -> o2 -> o1.isNone() ?
366+
Definition<A> oaDef = oa.def;
367+
return ordDef((o1, o2) -> o1.isNone() ?
284368
o2.isNone() ?
285369
Ordering.EQ :
286370
Ordering.LT :
287371
o2.isNone() ?
288372
Ordering.GT :
289-
oa.f.f(o1.some()).f(o2.some()));
373+
oaDef.compare(o1.some()).f(o2.some()));
290374
}
291375

292376
/**
@@ -297,13 +381,15 @@ public static <A> Ord<Option<A>> optionOrd(final Ord<A> oa) {
297381
* @return An order instance for the {@link Either} type.
298382
*/
299383
public static <A, B> Ord<Either<A, B>> eitherOrd(final Ord<A> oa, final Ord<B> ob) {
300-
return ord(e1 -> e2 -> e1.isLeft() ?
384+
Definition<A> oaDef = oa.def;
385+
Definition<B> obDef = ob.def;
386+
return ordDef((e1, e2) -> e1.isLeft() ?
301387
e2.isLeft() ?
302-
oa.f.f(e1.left().value()).f(e2.left().value()) :
303-
Ordering.LT :
388+
oaDef.compare(e1.left().value()).f(e2.left().value()) :
389+
Ordering.LT :
304390
e2.isLeft() ?
305-
Ordering.GT :
306-
ob.f.f(e1.right().value()).f(e2.right().value()));
391+
Ordering.GT :
392+
obDef.compare(e1.right().value()).f(e2.right().value()));
307393
}
308394

309395
/**
@@ -324,7 +410,7 @@ public static <A, B> Ord<Validation<A, B>> validationOrd(final Ord<A> oa, final
324410
* @return An order instance for the {@link List} type.
325411
*/
326412
public static <A> Ord<List<A>> listOrd(final Ord<A> oa) {
327-
return ord(l1 -> l2 -> {
413+
return ordDef((l1, l2) -> {
328414
List<A> x1 = l1;
329415
List<A> x2 = l2;
330416

@@ -364,14 +450,15 @@ public static <A> Ord<NonEmptyList<A>> nonEmptyListOrd(final Ord<A> oa) {
364450
* @return An order instance for the {@link Stream} type.
365451
*/
366452
public static <A> Ord<Stream<A>> streamOrd(final Ord<A> oa) {
367-
return ord(s1 -> s2 -> {
453+
return ordDef((s1, s2) -> {
368454
if (s1.isEmpty())
369455
return s2.isEmpty() ? Ordering.EQ : Ordering.LT;
370456
else if (s2.isEmpty())
371457
return s1.isEmpty() ? Ordering.EQ : Ordering.GT;
372458
else {
373459
final Ordering c = oa.compare(s1.head(), s2.head());
374-
return c == Ordering.EQ ? streamOrd(oa).f.f(s1.tail()._1()).f(s2.tail()._1()) : c;
460+
// FIXME: not stack safe
461+
return c == Ordering.EQ ? streamOrd(oa).def.compare(s1.tail()._1()).f(s2.tail()._1()) : c;
375462
}
376463
});
377464
}
@@ -383,7 +470,7 @@ else if (s2.isEmpty())
383470
* @return An order instance for the {@link Array} type.
384471
*/
385472
public static <A> Ord<Array<A>> arrayOrd(final Ord<A> oa) {
386-
return ord(a1 -> a2 -> {
473+
return ordDef((a1, a2) -> {
387474
int i = 0;
388475
//noinspection ForLoopWithMissingComponent
389476
for (; i < a1.length() && i < a2.length(); i++) {
@@ -414,7 +501,7 @@ public static <A> Ord<Set<A>> setOrd(final Ord<A> oa) {
414501
/**
415502
* An order instance for the {@link Unit} type.
416503
*/
417-
public static final Ord<Unit> unitOrd = ord(curry((Unit u1, Unit u2) -> Ordering.EQ));
504+
public static final Ord<Unit> unitOrd = ordDef((u1, u2) -> Ordering.EQ);
418505

419506
/**
420507
* An order instance for a product-1.
@@ -435,15 +522,15 @@ public static <A> Ord<P1<A>> p1Ord(final Ord<A> oa) {
435522
* @return An order instance for a product-2, with the first factor considered most significant.
436523
*/
437524
public static <A, B> Ord<P2<A, B>> p2Ord(final Ord<A> oa, final Ord<B> ob) {
438-
return ord(curry((P2<A, B> a, P2<A, B> b) -> oa.eq(a._1(), b._1()) ? ob.compare(a._2(), b._2()) : oa.compare(a._1(), b._1())));
525+
return ordDef((a, b) -> oa.eq(a._1(), b._1()) ? ob.compare(a._2(), b._2()) : oa.compare(a._1(), b._1()));
439526
}
440527

441528
public static <A, B> Ord<P2<A, B>> p2Ord1(Ord<A> oa) {
442-
return ord(p1 -> p2 -> oa.compare(p1._1(), p2._1()));
529+
return ordDef((p1, p2) -> oa.compare(p1._1(), p2._1()));
443530
}
444531

445532
public static <A, B> Ord<P2<A, B>> p2Ord2(Ord<B> ob) {
446-
return ord(p1 -> p2 -> ob.compare(p1._2(), p2._2()));
533+
return ordDef((p1, p2) -> ob.compare(p1._2(), p2._2()));
447534
}
448535

449536
/**
@@ -455,9 +542,9 @@ public static <A, B> Ord<P2<A, B>> p2Ord2(Ord<B> ob) {
455542
* @return An order instance for a product-3, with the first factor considered most significant.
456543
*/
457544
public static <A, B, C> Ord<P3<A, B, C>> p3Ord(final Ord<A> oa, final Ord<B> ob, final Ord<C> oc) {
458-
return ord(curry((P3<A, B, C> a, P3<A, B, C> b) -> oa.eq(a._1(), b._1()) ?
545+
return ordDef((a, b) -> oa.eq(a._1(), b._1()) ?
459546
p2Ord(ob, oc).compare(P.p(a._2(), a._3()), P.p(b._2(), b._3()))
460-
: oa.compare(a._1(), b._1())));
547+
: oa.compare(a._1(), b._1()));
461548
}
462549

463550
/**
@@ -472,8 +559,7 @@ public static <A, B, C> Ord<P3<A, B, C>> p3Ord(final Ord<A> oa, final Ord<B> ob,
472559
* @return An order instance for the <code>Comparable</code> interface.
473560
*/
474561
public static <A extends Comparable<A>> Ord<A> comparableOrd() {
475-
476-
return ord(a1 -> a2 -> Ordering.fromInt(a1.compareTo(a2)));
562+
return ordDef((a1, a2) -> Ordering.fromInt(a1.compareTo(a2)));
477563
}
478564

479565
/**
@@ -485,7 +571,7 @@ public static <A extends Comparable<A>> Ord<A> comparableOrd() {
485571
* @see #hashEqualsOrd()
486572
*/
487573
public static <A> Ord<A> hashOrd() {
488-
return ord(a -> {
574+
return ordDef(a -> {
489575
int aHash = a.hashCode();
490576
return a2 -> Ordering.fromInt(Integer.compare(aHash, a2.hashCode()));
491577
});
@@ -499,7 +585,7 @@ public static <A> Ord<A> hashOrd() {
499585
* @return An order instance that is based on {@link Object#hashCode()} and {@link Object#equals}.
500586
*/
501587
public static <A> Ord<A> hashEqualsOrd() {
502-
return ord(a -> {
588+
return ordDef(a -> {
503589
int aHash = a.hashCode();
504590
return a2 -> {
505591
final int a2Hash = a2.hashCode();

0 commit comments

Comments
 (0)