Skip to content

Commit c4f1f68

Browse files
committed
Move fluent Equal/Ord construction api to the Definition interfaces.
Also remove Equal.or and Equal.and as there is no precise use case.
1 parent dc0f405 commit c4f1f68

File tree

4 files changed

+117
-127
lines changed

4 files changed

+117
-127
lines changed

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

Lines changed: 52 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,39 @@ public interface Definition<A> {
4848
default boolean equal(A a1, A a2) {
4949
return equal(a1).f(a2);
5050
}
51+
52+
/**
53+
* Refine this equal definition, to tests equality of self and the mapped object in "and" manner.
54+
* @see #equal()
55+
*
56+
* @param f The function to map the original object
57+
* @param eq Equality for the mapped object
58+
* @return A new equal definition
59+
*/
60+
default <B> Definition<A> then(final F<A, B> f, final Equal<B> eq) {
61+
Definition<B> bEqDef = eq.def;
62+
return new Definition<A>() {
63+
@Override
64+
public F<A, Boolean> equal(A a1) {
65+
F<A, Boolean> fa = Definition.this.equal(a1);
66+
F<B, Boolean> fb = bEqDef.equal(f.f(a1));
67+
return a2 -> fa.f(a2) && fb.f(f.f(a2));
68+
}
69+
70+
@Override
71+
public boolean equal(A a1, A a2) {
72+
return Definition.this.equal(a1, a2) && bEqDef.equal(f.f(a1), f.f(a2));
73+
}
74+
};
75+
}
76+
77+
/**
78+
* Build an equal instance from this definition.
79+
* to be called after some successive {@link #then(F, Equal)} calls.
80+
*/
81+
default Equal<A> equal() {
82+
return equalDef(this);
83+
}
5184
}
5285

5386
/**
@@ -118,58 +151,31 @@ public F<A, Boolean> eq(final A a) {
118151
* @return A new equal.
119152
*/
120153
public <B> Equal<B> contramap(final F<B, A> f) {
121-
Definition<A> eaDef = def;
122-
return equalDef(new Definition<B>(){
123-
@Override
124-
public F<B, Boolean> equal(B b) {
125-
return compose(eaDef.equal(f.f(b)), f);
126-
}
127-
128-
@Override
129-
public boolean equal(B b1, B b2) {
130-
return eaDef.equal(f.f(b1), f.f(b2));
131-
}
132-
});
154+
return equalDef(contramapDef(f, def));
133155
}
134156

135157
/**
136-
* Constructs an equal instance, which tests equality of self and the mapped object in "and" manner
158+
* An equal instance, which reverts equality for self
137159
*
138-
* @param f The function to map the original object
139-
* @param eq Equality for the mapped object
140160
* @return A new equal instance
141161
*/
142-
public final <B> Equal<A> andThen(final F<A, B> f, final Equal<B> eq) {
143-
return and(eq.contramap(f));
162+
public final Equal<A> not() {
163+
return equalDef((a1, a2) -> !def.equal(a1, a2));
144164
}
145165

146-
/**
147-
* An equal instance, which executes two Equality of self in "and" manner
148-
*
149-
* @param eq Another equality for self
150-
* @return A new equal instance
151-
*/
152-
public final Equal<A> and(final Equal<A> eq) {
153-
return equalDef((a1, a2) -> def.equal(a1, a2) && eq.def.equal(a1, a2));
154-
}
155166

156-
/**
157-
* An equal instance, which executes two Equality of self in "or" manner
158-
*
159-
* @param eq Another equality for self
160-
* @return A new equal instance
161-
*/
162-
public final Equal<A> or(final Equal<A> eq) {
163-
return equalDef((a1, a2) -> def.equal(a1, a2) || eq.def.equal(a1, a2));
164-
}
167+
private static <A, B> Definition<B> contramapDef(F<B, A> f, Definition<A> aEqDef) {
168+
return new Definition<B>(){
169+
@Override
170+
public F<B, Boolean> equal(B b) {
171+
return compose(aEqDef.equal(f.f(b)), f);
172+
}
165173

166-
/**
167-
* An equal instance, which reverts equality for self
168-
*
169-
* @return A new equal instance
170-
*/
171-
public final Equal<A> not() {
172-
return equalDef((a1, a2) -> !def.equal(a1, a2));
174+
@Override
175+
public boolean equal(B b1, B b2) {
176+
return aEqDef.equal(f.f(b1), f.f(b2));
177+
}
178+
};
173179
}
174180

175181
/**
@@ -180,24 +186,11 @@ public static <A, B> Equal<A> contramap(final F<A, B> f, final Equal<B> eq) {
180186
}
181187

182188
/**
183-
* Static version of {@link #and(Equal)}
184-
*/
185-
public static <A> Equal<A> and(final Equal<A> eq1, final Equal<A> eq2) {
186-
return eq1.and(eq2);
187-
}
188-
189-
/**
190-
* Static version of {@link #or(Equal)}
191-
*/
192-
public static <A> Equal<A> or(final Equal<A> eq1, final Equal<A> eq2) {
193-
return eq1.or(eq2);
194-
}
195-
196-
/**
197-
* Static version of {@link #not()}
189+
* Begin definition of an equal instance.
190+
* @see Definition#then(F, Equal)
198191
*/
199-
public static <A> Equal<A> not(final Equal<A> eq) {
200-
return eq.not();
192+
public static <A, B> Definition<A> on(final F<A, B> f, final Equal<B> eq) {
193+
return contramapDef(f, eq.def);
201194
}
202195

203196
/**

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

Lines changed: 60 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,42 @@ public Definition<A> dual() {
8484
}
8585
};
8686
}
87+
88+
/**
89+
* Refine this ord definition: compares using self and if objects are equal compares using given <code>Ord</code>.
90+
* @see #ord()
91+
*
92+
* @param bOrd Ord for subsequent comparison
93+
* @return A new ord definition.
94+
*/
95+
default <B> Definition<A> then(final F<A, B> f, final Ord<B> bOrd) {
96+
Definition<B> bOrdDef = bOrd.def;
97+
return new Definition<A>() {
98+
@Override
99+
public F<A, Ordering> compare(A a1) {
100+
F<A, Ordering> fa = Definition.this.compare(a1);
101+
F<B, Ordering> fb = bOrdDef.compare(f.f(a1));
102+
return a2 -> {
103+
Ordering aOrdering = fa.f(a2);
104+
return aOrdering != Ordering.EQ ? aOrdering : fb.f(f.f(a2));
105+
};
106+
}
107+
108+
@Override
109+
public Ordering compare(A a1, A a2) {
110+
Ordering aOrdering = Definition.this.compare(a1, a2);
111+
return aOrdering != Ordering.EQ ? aOrdering : bOrdDef.compare(f.f(a1), f.f(a2));
112+
}
113+
};
114+
}
115+
116+
/**
117+
* Build an ord instance from this definition.
118+
* to be called after some successive {@link #then(F, Ord)} calls.
119+
*/
120+
default Ord<A> ord() {
121+
return ordDef(this);
122+
}
87123
}
88124

89125
/**
@@ -160,18 +196,7 @@ public Equal<A> equal() {
160196
* @return A new ord.
161197
*/
162198
public <B> Ord<B> contramap(final F<B, A> f) {
163-
Definition<A> selfDef = def;
164-
return ordDef(new Definition<B>() {
165-
@Override
166-
public F<B, Ordering> compare(B b) {
167-
return compose(selfDef.compare(f.f(b)), f);
168-
}
169-
170-
@Override
171-
public Ordering compare(B b1, B b2) {
172-
return selfDef.compare(f.f(b1), f.f(b2));
173-
}
174-
});
199+
return ordDef(contramapDef(f, def));
175200
}
176201

177202
/**
@@ -288,36 +313,32 @@ public final Ord<A> reverse() {
288313
}
289314

290315
/**
291-
* Constructs an ord instance, which compares using self and if objects are equal compares using <code>ord</code>
292-
*
293-
* @param ord Ord for subsequent comparison
294-
* @return A new equal instance
316+
* Begin definition of an ord instance.
317+
* @see Definition#then(F, Equal)
295318
*/
296-
public final Ord<A> andThen(final Ord<A> ord) {
297-
return ordDef((a1, a2) -> {
298-
final Ordering compareResult = compare(a1, a2);
299-
if(compareResult == Ordering.EQ)
300-
return ord.compare(a1, a2);
301-
return compareResult;
302-
});
303-
}
304-
305-
/**
306-
* Constructs an ord instance, which compares using self and if objects are equal compares the mapped objects
307-
*
308-
* @param f The function to map the original object
309-
* @param ord Ord for the mapped object
310-
* @return A new equal instance
311-
*/
312-
public final <B> Ord<A> andThen(final F<A, B> f, final Ord<B> ord) {
313-
return andThen(ord.contramap(f));
319+
public static <A, B> Definition<A> on(final F<A, B> f, final Ord<B> ord) {
320+
return contramapDef(f, ord.def);
314321
}
315322

316323
/**
317324
* Static version of {@link #contramap(F)}
318325
*/
319326
public static <A, B> Ord<A> contramap(final F<A, B> f, final Ord<B> ord) {
320-
return ord.contramap(f);
327+
return ordDef(contramapDef(f, ord.def));
328+
}
329+
330+
private static <A, B> Definition<B> contramapDef(F<B, A> f, Definition<A> def) {
331+
return new Definition<B>() {
332+
@Override
333+
public F<B, Ordering> compare(B b) {
334+
return compose(def.compare(f.f(b)), f);
335+
}
336+
337+
@Override
338+
public Ordering compare(B b1, B b2) {
339+
return def.compare(f.f(b1), f.f(b2));
340+
}
341+
};
321342
}
322343

323344
/**
@@ -609,15 +630,15 @@ public static <A> Ord<P1<A>> p1Ord(final Ord<A> oa) {
609630
* @return An order instance for a product-2, with the first factor considered most significant.
610631
*/
611632
public static <A, B> Ord<P2<A, B>> p2Ord(final Ord<A> oa, final Ord<B> ob) {
612-
return ordDef((a, b) -> oa.eq(a._1(), b._1()) ? ob.compare(a._2(), b._2()) : oa.compare(a._1(), b._1()));
633+
return on(P2.<A, B>__1(), oa).then(P2.__2(), ob).ord();
613634
}
614635

615636
public static <A, B> Ord<P2<A, B>> p2Ord1(Ord<A> oa) {
616-
return ordDef((p1, p2) -> oa.compare(p1._1(), p2._1()));
637+
return on(P2.<A, B>__1(), oa).ord();
617638
}
618639

619640
public static <A, B> Ord<P2<A, B>> p2Ord2(Ord<B> ob) {
620-
return ordDef((p1, p2) -> ob.compare(p1._2(), p2._2()));
641+
return on(P2.<A, B>__2(), ob).ord();
621642
}
622643

623644
/**
@@ -629,9 +650,7 @@ public static <A, B> Ord<P2<A, B>> p2Ord2(Ord<B> ob) {
629650
* @return An order instance for a product-3, with the first factor considered most significant.
630651
*/
631652
public static <A, B, C> Ord<P3<A, B, C>> p3Ord(final Ord<A> oa, final Ord<B> ob, final Ord<C> oc) {
632-
return ordDef((a, b) -> oa.eq(a._1(), b._1()) ?
633-
p2Ord(ob, oc).compare(P.p(a._2(), a._3()), P.p(b._2(), b._3()))
634-
: oa.compare(a._1(), b._1()));
653+
return on(P3.<A, B, C>__1(), oa).then(P3.__2(), ob).then(P3.__3(), oc).ord();
635654
}
636655

637656
/**

core/src/test/java/fj/EqualTest.java

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,10 @@ public void contramapShouldWork() {
1414
assertThat(equalByLength.eq("str1", "str11"), is(false));
1515
}
1616

17-
@Test
18-
public void andShouldWork() {
19-
Equal<String> equalByLengthAndLastDigit = Equal.and(Equal.contramap(String::length, Equal.intEqual),
20-
Equal.contramap(s -> s.charAt(s.length() - 1),
21-
Equal.charEqual));
22-
23-
assertThat(equalByLengthAndLastDigit.eq("str1", "spr1"), is(true));
24-
assertThat(equalByLengthAndLastDigit.eq("str1", "str2"), is(false));
25-
assertThat(equalByLengthAndLastDigit.eq("str1", "strr1"), is(false));
26-
}
27-
28-
@Test
29-
public void orShouldWork() {
30-
Equal<String> equalByLengthOrLastDigit = Equal.or(Equal.contramap(String::length, Equal.intEqual),
31-
Equal.contramap(s -> s.charAt(s.length() - 1),
32-
Equal.charEqual));
33-
34-
assertThat(equalByLengthOrLastDigit.eq("str1", "str2"), is(true));
35-
assertThat(equalByLengthOrLastDigit.eq("str1", "strr1"), is(true));
36-
assertThat(equalByLengthOrLastDigit.eq("str1", "strr2"), is(false));
37-
}
38-
3917
@Test
4018
public void thenShouldWork() {
41-
Equal<String> equalByLengthThenLastDigit = Equal.contramap(String::length, Equal.intEqual)
42-
.andThen(s -> s.charAt(s.length() - 1), Equal.charEqual);
19+
Equal<String> equalByLengthThenLastDigit = Equal.on(String::length, Equal.intEqual)
20+
.then(s -> s.charAt(s.length() - 1), Equal.charEqual).equal();
4321

4422
assertThat(equalByLengthThenLastDigit.eq("str1", "spr1"), is(true));
4523
assertThat(equalByLengthThenLastDigit.eq("str1", "str2"), is(false));

core/src/test/java/fj/OrdTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ public void contramapShouldWork() {
3434
}
3535

3636
@Test
37-
public void andThenShouldWork() {
38-
Ord<String> lengthThenLastDigitOrd = Ord.contramap(String::length, Ord.intOrd)
39-
.andThen(s -> s.charAt(s.length() - 1), Ord.charOrd);
37+
public void thenShouldWork() {
38+
Ord<String> lengthThenLastDigitOrd = Ord.on(String::length, Ord.intOrd)
39+
.then(s -> s.charAt(s.length() - 1), Ord.charOrd).ord();
4040

4141
assertThat(lengthThenLastDigitOrd.compare("str", "dyr"), is(Ordering.EQ));
4242
assertThat(lengthThenLastDigitOrd.compare("stt", "str"), is(Ordering.GT));

0 commit comments

Comments
 (0)