comparison src/main/java/fj/Ord.java @ 0:fe80c1edf1be

add getLoop
author tatsuki
date Fri, 20 Mar 2015 21:04:03 +0900
parents
children 8ed7d71e8617
comparison
equal deleted inserted replaced
-1:000000000000 0:fe80c1edf1be
1 package fj;
2
3 import fj.data.Array;
4 import fj.data.Either;
5 import fj.data.List;
6 import fj.data.Natural;
7 import fj.data.NonEmptyList;
8 import fj.data.Option;
9 import fj.data.Set;
10 import fj.data.Stream;
11 import fj.data.Validation;
12
13 import java.math.BigDecimal;
14 import java.math.BigInteger;
15
16 import static fj.Function.curry;
17
18 /**
19 * Tests for ordering between two objects.
20 *
21 * @version %build.number%
22 */
23 public final class Ord<A> {
24 private final F<A, F<A, Ordering>> f;
25
26 private Ord(final F<A, F<A, Ordering>> f) {
27 this.f = f;
28 }
29
30 /**
31 * First-class ordering.
32 *
33 * @return A function that returns an ordering for its arguments.
34 */
35 public F<A, F<A, Ordering>> compare() {
36 return f;
37 }
38
39 /**
40 * Returns an ordering for the given arguments.
41 *
42 * @param a1 An instance to compare for ordering to another.
43 * @param a2 An instance to compare for ordering to another.
44 * @return An ordering for the given arguments.
45 */
46 public Ordering compare(final A a1, final A a2) {
47 return f.f(a1).f(a2);
48 }
49
50 /**
51 * Returns <code>true</code> if the given arguments are equal, <code>false</code> otherwise.
52 *
53 * @param a1 An instance to compare for equality to another.
54 * @param a2 An instance to compare for equality to another.
55 * @return <code>true</code> if the given arguments are equal, <code>false</code> otherwise.
56 */
57 public boolean eq(final A a1, final A a2) {
58 return compare(a1, a2) == Ordering.EQ;
59 }
60
61 /**
62 * Returns an <code>Equal</code> for this order.
63 *
64 * @return An <code>Equal</code> for this order.
65 */
66 public Equal<A> equal() {
67 return Equal.equal(curry(new F2<A, A, Boolean>() {
68 public Boolean f(final A a1, final A a2) {
69 return eq(a1, a2);
70 }
71 }));
72 }
73
74 /**
75 * Maps the given function across this ord as a contra-variant functor.
76 *
77 * @param f The function to map.
78 * @return A new ord.
79 */
80 public <B> Ord<B> comap(final F<B, A> f) {
81 return ord(F1Functions.o(F1Functions.o(F1Functions.<B, A, Ordering>andThen(f), this.f), f));
82 }
83
84 /**
85 * Returns <code>true</code> if the first given argument is less than the second given argument,
86 * <code>false</code> otherwise.
87 *
88 * @param a1 An instance to compare for ordering to another.
89 * @param a2 An instance to compare for ordering to another.
90 * @return <code>true</code> if the first given argument is less than the second given argument,
91 * <code>false</code> otherwise.
92 */
93 public boolean isLessThan(final A a1, final A a2) {
94 return compare(a1, a2) == Ordering.LT;
95 }
96
97 /**
98 * Returns <code>true</code> if the first given argument is greater than the second given
99 * argument, <code>false</code> otherwise.
100 *
101 * @param a1 An instance to compare for ordering to another.
102 * @param a2 An instance to compare for ordering to another.
103 * @return <code>true</code> if the first given argument is greater than the second given
104 * argument, <code>false</code> otherwise.
105 */
106 public boolean isGreaterThan(final A a1, final A a2) {
107 return compare(a1, a2) == Ordering.GT;
108 }
109
110 /**
111 * Returns a function that returns true if its argument is less than the argument to this method.
112 *
113 * @param a A value to compare against.
114 * @return A function that returns true if its argument is less than the argument to this method.
115 */
116 public F<A, Boolean> isLessThan(final A a) {
117 return new F<A, Boolean>() {
118 public Boolean f(final A a2) {
119 return compare(a2, a) == Ordering.LT;
120 }
121 };
122 }
123
124 /**
125 * Returns a function that returns true if its argument is greater than than the argument to this method.
126 *
127 * @param a A value to compare against.
128 * @return A function that returns true if its argument is greater than the argument to this method.
129 */
130 public F<A, Boolean> isGreaterThan(final A a) {
131 return new F<A, Boolean>() {
132 public Boolean f(final A a2) {
133 return compare(a2, a) == Ordering.GT;
134 }
135 };
136 }
137
138 /**
139 * Returns the greater of its two arguments.
140 *
141 * @param a1 A value to compare with another.
142 * @param a2 A value to compare with another.
143 * @return The greater of the two values.
144 */
145 public A max(final A a1, final A a2) {
146 return isGreaterThan(a1, a2) ? a1 : a2;
147 }
148
149
150 /**
151 * Returns the lesser of its two arguments.
152 *
153 * @param a1 A value to compare with another.
154 * @param a2 A value to compare with another.
155 * @return The lesser of the two values.
156 */
157 public A min(final A a1, final A a2) {
158 return isLessThan(a1, a2) ? a1 : a2;
159 }
160
161 /**
162 * A function that returns the greater of its two arguments.
163 */
164 public final F<A, F<A, A>> max = curry(new F2<A, A, A>() {
165 public A f(final A a, final A a1) {
166 return max(a, a1);
167 }
168 });
169
170 /**
171 * A function that returns the lesser of its two arguments.
172 */
173 public final F<A, F<A, A>> min = curry(new F2<A, A, A>() {
174 public A f(final A a, final A a1) {
175 return min(a, a1);
176 }
177 });
178
179 /**
180 * Returns an order instance that uses the given equality test and ordering function.
181 *
182 * @param f The order function.
183 * @return An order instance.
184 */
185 public static <A> Ord<A> ord(final F<A, F<A, Ordering>> f) {
186 return new Ord<A>(f);
187 }
188
189 /**
190 * An order instance for the <code>boolean</code> type.
191 */
192 public static final Ord<Boolean> booleanOrd = new Ord<Boolean>(
193 new F<Boolean, F<Boolean, Ordering>>() {
194 public F<Boolean, Ordering> f(final Boolean a1) {
195 return new F<Boolean, Ordering>() {
196 public Ordering f(final Boolean a2) {
197 final int x = a1.compareTo(a2);
198 return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
199 }
200 };
201 }
202 });
203
204 /**
205 * An order instance for the <code>byte</code> type.
206 */
207 public static final Ord<Byte> byteOrd = new Ord<Byte>(
208 new F<Byte, F<Byte, Ordering>>() {
209 public F<Byte, Ordering> f(final Byte a1) {
210 return new F<Byte, Ordering>() {
211 public Ordering f(final Byte a2) {
212 final int x = a1.compareTo(a2);
213 return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
214 }
215 };
216 }
217 });
218
219 /**
220 * An order instance for the <code>char</code> type.
221 */
222 public static final Ord<Character> charOrd = new Ord<Character>(
223 new F<Character, F<Character, Ordering>>() {
224 public F<Character, Ordering> f(final Character a1) {
225 return new F<Character, Ordering>() {
226 public Ordering f(final Character a2) {
227 final int x = a1.compareTo(a2);
228 return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
229 }
230 };
231 }
232 });
233
234 /**
235 * An order instance for the <code>double</code> type.
236 */
237 public static final Ord<Double> doubleOrd = new Ord<Double>(
238 new F<Double, F<Double, Ordering>>() {
239 public F<Double, Ordering> f(final Double a1) {
240 return new F<Double, Ordering>() {
241 public Ordering f(final Double a2) {
242 final int x = a1.compareTo(a2);
243 return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
244 }
245 };
246 }
247 });
248
249 /**
250 * An order instance for the <code>float</code> type.
251 */
252 public static final Ord<Float> floatOrd = new Ord<Float>(
253 new F<Float, F<Float, Ordering>>() {
254 public F<Float, Ordering> f(final Float a1) {
255 return new F<Float, Ordering>() {
256 public Ordering f(final Float a2) {
257 final int x = a1.compareTo(a2);
258 return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
259 }
260 };
261 }
262 });
263
264 /**
265 * An order instance for the <code>int</code> type.
266 */
267 public static final Ord<Integer> intOrd = new Ord<Integer>(
268 new F<Integer, F<Integer, Ordering>>() {
269 public F<Integer, Ordering> f(final Integer a1) {
270 return new F<Integer, Ordering>() {
271 public Ordering f(final Integer a2) {
272 final int x = a1.compareTo(a2);
273 return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
274 }
275 };
276 }
277 });
278
279 /**
280 * An order instance for the <code>BigInteger</code> type.
281 */
282 public static final Ord<BigInteger> bigintOrd = new Ord<BigInteger>(
283 new F<BigInteger, F<BigInteger, Ordering>>() {
284 public F<BigInteger, Ordering> f(final BigInteger a1) {
285 return new F<BigInteger, Ordering>() {
286 public Ordering f(final BigInteger a2) {
287 final int x = a1.compareTo(a2);
288 return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
289 }
290 };
291 }
292 });
293
294 /**
295 * An order instance for the <code>BigDecimal</code> type.
296 */
297 public static final Ord<BigDecimal> bigdecimalOrd = new Ord<BigDecimal>(
298 new F<BigDecimal, F<BigDecimal, Ordering>>() {
299 public F<BigDecimal, Ordering> f(final BigDecimal a1) {
300 return new F<BigDecimal, Ordering>() {
301 public Ordering f(final BigDecimal a2) {
302 final int x = a1.compareTo(a2);
303 return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
304 }
305 };
306 }
307 });
308
309 /**
310 * An order instance for the <code>long</code> type.
311 */
312 public static final Ord<Long> longOrd = new Ord<Long>(
313 new F<Long, F<Long, Ordering>>() {
314 public F<Long, Ordering> f(final Long a1) {
315 return new F<Long, Ordering>() {
316 public Ordering f(final Long a2) {
317 final int x = a1.compareTo(a2);
318 return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
319 }
320 };
321 }
322 });
323
324 /**
325 * An order instance for the <code>short</code> type.
326 */
327 public static final Ord<Short> shortOrd = new Ord<Short>(
328 new F<Short, F<Short, Ordering>>() {
329 public F<Short, Ordering> f(final Short a1) {
330 return new F<Short, Ordering>() {
331 public Ordering f(final Short a2) {
332 final int x = a1.compareTo(a2);
333 return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
334 }
335 };
336 }
337 });
338
339 /**
340 * An order instance for the {@link Ordering} type.
341 */
342 public static final Ord<Ordering> orderingOrd = new Ord<Ordering>(curry(new F2<Ordering, Ordering, Ordering>() {
343 public Ordering f(final Ordering o1, final Ordering o2) {
344 return o1 == o2 ?
345 Ordering.EQ :
346 o1 == Ordering.LT ?
347 Ordering.LT :
348 o2 == Ordering.LT ?
349 Ordering.GT :
350 o1 == Ordering.EQ ?
351 Ordering.LT :
352 Ordering.GT;
353 }
354 }));
355
356 /**
357 * An order instance for the {@link String} type.
358 */
359 public static final Ord<String> stringOrd = new Ord<String>(
360 new F<String, F<String, Ordering>>() {
361 public F<String, Ordering> f(final String a1) {
362 return new F<String, Ordering>() {
363 public Ordering f(final String a2) {
364 final int x = a1.compareTo(a2);
365 return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
366 }
367 };
368 }
369 });
370
371 /**
372 * An order instance for the {@link StringBuffer} type.
373 */
374 public static final Ord<StringBuffer> stringBufferOrd =
375 new Ord<StringBuffer>(new F<StringBuffer, F<StringBuffer, Ordering>>() {
376 public F<StringBuffer, Ordering> f(final StringBuffer a1) {
377 return new F<StringBuffer, Ordering>() {
378 public Ordering f(final StringBuffer a2) {
379 return stringOrd.compare(a1.toString(), a2.toString());
380 }
381 };
382 }
383 });
384
385 /**
386 * An order instance for the {@link StringBuffer} type.
387 */
388 public static final Ord<StringBuilder> stringBuilderOrd =
389 new Ord<StringBuilder>(new F<StringBuilder, F<StringBuilder, Ordering>>() {
390 public F<StringBuilder, Ordering> f(final StringBuilder a1) {
391 return new F<StringBuilder, Ordering>() {
392 public Ordering f(final StringBuilder a2) {
393 return stringOrd.compare(a1.toString(), a2.toString());
394 }
395 };
396 }
397 });
398
399 /**
400 * An order instance for the {@link Option} type.
401 *
402 * @param oa Order across the element of the option.
403 * @return An order instance for the {@link Option} type.
404 */
405 public static <A> Ord<Option<A>> optionOrd(final Ord<A> oa) {
406 return new Ord<Option<A>>(new F<Option<A>, F<Option<A>, Ordering>>() {
407 public F<Option<A>, Ordering> f(final Option<A> o1) {
408 return new F<Option<A>, Ordering>() {
409 public Ordering f(final Option<A> o2) {
410 return o1.isNone() ?
411 o2.isNone() ?
412 Ordering.EQ :
413 Ordering.LT :
414 o2.isNone() ?
415 Ordering.GT :
416 oa.f.f(o1.some()).f(o2.some());
417 }
418 };
419 }
420 });
421 }
422
423 /**
424 * An order instance for the {@link Either} type.
425 *
426 * @param oa Order across the left side of {@link Either}.
427 * @param ob Order across the right side of {@link Either}.
428 * @return An order instance for the {@link Either} type.
429 */
430 public static <A, B> Ord<Either<A, B>> eitherOrd(final Ord<A> oa, final Ord<B> ob) {
431 return new Ord<Either<A, B>>(new F<Either<A, B>, F<Either<A, B>, Ordering>>() {
432 public F<Either<A, B>, Ordering> f(final Either<A, B> e1) {
433 return new F<Either<A, B>, Ordering>() {
434 public Ordering f(final Either<A, B> e2) {
435 return e1.isLeft() ?
436 e2.isLeft() ?
437 oa.f.f(e1.left().value()).f(e2.left().value()) :
438 Ordering.LT :
439 e2.isLeft() ?
440 Ordering.GT :
441 ob.f.f(e1.right().value()).f(e2.right().value());
442 }
443 };
444 }
445 });
446 }
447
448 /**
449 * An order instance for the {@link Validation} type.
450 *
451 * @param oa Order across the failing side of {@link Validation}.
452 * @param ob Order across the succeeding side of {@link Validation}.
453 * @return An order instance for the {@link Validation} type.
454 */
455 public static <A, B> Ord<Validation<A, B>> validationOrd(final Ord<A> oa, final Ord<B> ob) {
456 return eitherOrd(oa, ob).comap(Validation.<A, B>either());
457 }
458
459 /**
460 * An order instance for the {@link List} type.
461 *
462 * @param oa Order across the elements of the list.
463 * @return An order instance for the {@link List} type.
464 */
465 public static <A> Ord<List<A>> listOrd(final Ord<A> oa) {
466 return new Ord<List<A>>(new F<List<A>, F<List<A>, Ordering>>() {
467 public F<List<A>, Ordering> f(final List<A> l1) {
468 return new F<List<A>, Ordering>() {
469 public Ordering f(final List<A> l2) {
470 if (l1.isEmpty())
471 return l2.isEmpty() ? Ordering.EQ : Ordering.LT;
472 else if (l2.isEmpty())
473 return l1.isEmpty() ? Ordering.EQ : Ordering.GT;
474 else {
475 final Ordering c = oa.compare(l1.head(), l2.head());
476 return c == Ordering.EQ ? listOrd(oa).f.f(l1.tail()).f(l2.tail()) : c;
477 }
478 }
479 };
480 }
481 });
482 }
483
484 /**
485 * An order instance for the {@link NonEmptyList} type.
486 *
487 * @param oa Order across the elements of the non-empty list.
488 * @return An order instance for the {@link NonEmptyList} type.
489 */
490 public static <A> Ord<NonEmptyList<A>> nonEmptyListOrd(final Ord<A> oa) {
491 return listOrd(oa).comap(NonEmptyList.<A>toList_());
492 }
493
494 /**
495 * An order instance for the {@link Stream} type.
496 *
497 * @param oa Order across the elements of the stream.
498 * @return An order instance for the {@link Stream} type.
499 */
500 public static <A> Ord<Stream<A>> streamOrd(final Ord<A> oa) {
501 return new Ord<Stream<A>>(new F<Stream<A>, F<Stream<A>, Ordering>>() {
502 public F<Stream<A>, Ordering> f(final Stream<A> s1) {
503 return new F<Stream<A>, Ordering>() {
504 public Ordering f(final Stream<A> s2) {
505 if (s1.isEmpty())
506 return s2.isEmpty() ? Ordering.EQ : Ordering.LT;
507 else if (s2.isEmpty())
508 return s1.isEmpty() ? Ordering.EQ : Ordering.GT;
509 else {
510 final Ordering c = oa.compare(s1.head(), s2.head());
511 return c == Ordering.EQ ? streamOrd(oa).f.f(s1.tail()._1()).f(s2.tail()._1()) : c;
512 }
513 }
514 };
515 }
516 });
517 }
518
519 /**
520 * An order instance for the {@link Array} type.
521 *
522 * @param oa Order across the elements of the array.
523 * @return An order instance for the {@link Array} type.
524 */
525 public static <A> Ord<Array<A>> arrayOrd(final Ord<A> oa) {
526 return new Ord<Array<A>>(new F<Array<A>, F<Array<A>, Ordering>>() {
527 public F<Array<A>, Ordering> f(final Array<A> a1) {
528 return new F<Array<A>, Ordering>() {
529 public Ordering f(final Array<A> a2) {
530 int i = 0;
531 //noinspection ForLoopWithMissingComponent
532 for (; i < a1.length() && i < a2.length(); i++) {
533 final Ordering c = oa.compare(a1.get(i), a2.get(i));
534 if (c == Ordering.GT || c == Ordering.LT)
535 return c;
536 }
537 return i == a1.length() ?
538 i == a2.length() ?
539 Ordering.EQ :
540 Ordering.LT :
541 i == a1.length() ?
542 Ordering.EQ :
543 Ordering.GT;
544 }
545 };
546 }
547 });
548 }
549
550 /**
551 * An order instance for the {@link Set} type.
552 *
553 * @param oa Order across the elements of the set.
554 * @return An order instance for the {@link Set} type.
555 */
556 public static <A> Ord<Set<A>> setOrd(final Ord<A> oa) {
557 return streamOrd(oa).comap(new F<Set<A>, Stream<A>>() {
558 public Stream<A> f(final Set<A> as) {
559 return as.toStream();
560 }
561 });
562 }
563
564 /**
565 * An order instance for the {@link Unit} type.
566 */
567 public static final Ord<Unit> unitOrd = ord(curry(new F2<Unit, Unit, Ordering>() {
568 public Ordering f(final Unit u1, final Unit u2) {
569 return Ordering.EQ;
570 }
571 }));
572
573 /**
574 * An order instance for a product-1.
575 *
576 * @param oa Order across the produced type.
577 * @return An order instance for a product-1.
578 */
579 public static <A> Ord<P1<A>> p1Ord(final Ord<A> oa) {
580 return oa.comap(P1.<A>__1());
581 }
582
583
584 /**
585 * An order instance for a product-2, with the first factor considered most significant.
586 *
587 * @param oa An order instance for the first factor.
588 * @param ob An order instance for the second factor.
589 * @return An order instance for a product-2, with the first factor considered most significant.
590 */
591 public static <A, B> Ord<P2<A, B>> p2Ord(final Ord<A> oa, final Ord<B> ob) {
592 return ord(curry(new F2<P2<A, B>, P2<A, B>, Ordering>() {
593 public Ordering f(final P2<A, B> a, final P2<A, B> b) {
594 return oa.eq(a._1(), b._1()) ? ob.compare(a._2(), b._2()) : oa.compare(a._1(), b._1());
595 }
596 }));
597 }
598
599 /**
600 * An order instance for a product-3, with the first factor considered most significant.
601 *
602 * @param oa An order instance for the first factor.
603 * @param ob An order instance for the second factor.
604 * @param oc An order instance for the third factor.
605 * @return An order instance for a product-3, with the first factor considered most significant.
606 */
607 public static <A, B, C> Ord<P3<A, B, C>> p3Ord(final Ord<A> oa, final Ord<B> ob, final Ord<C> oc) {
608 return ord(curry(new F2<P3<A, B, C>, P3<A, B, C>, Ordering>() {
609 public Ordering f(final P3<A, B, C> a, final P3<A, B, C> b) {
610 return oa.eq(a._1(), b._1()) ?
611 p2Ord(ob, oc).compare(P.p(a._2(), a._3()), P.p(b._2(), b._3()))
612 : oa.compare(a._1(), b._1());
613 }
614 }));
615 }
616
617 /**
618 * An order instance for the <code>Natural</code> type.
619 */
620 public static final Ord<Natural> naturalOrd = bigintOrd.comap(Natural.bigIntegerValue);
621
622
623 /**
624 * An order instance for the <code>Comparable</code> interface.
625 *
626 * @return An order instance for the <code>Comparable</code> interface.
627 */
628 public static <A extends Comparable<A>> Ord<A> comparableOrd() {
629 return ord(new F<A, F<A, Ordering>>() {
630 public F<A, Ordering> f(final A a1) {
631 return new F<A, Ordering>() {
632 public Ordering f(final A a2) {
633 return Ordering.fromInt(a1.compareTo(a2));
634 }
635 };
636 }
637 });
638 }
639
640 /**
641 * An order instance that uses {@link Object#hashCode()} for computing the order and equality,
642 * thus objects returning the same hashCode are considered to be equals (check {@link #hashEqualsOrd()}
643 * for an additional check on {@link Object#equals(Object)}).
644 *
645 * @return An order instance that is based on {@link Object#hashCode()}.
646 * @see #hashEqualsOrd()
647 */
648 public static <A> Ord<A> hashOrd() {
649 return Ord.<A> ord(new F<A, F<A, Ordering>>() {
650 @Override
651 public F<A, Ordering> f(final A a) {
652 return new F<A, Ordering>() {
653 @Override
654 public Ordering f(final A a2) {
655 final int x = a.hashCode() - a2.hashCode();
656 return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
657 }
658 };
659 }
660 });
661 }
662
663 /**
664 * An order instance that uses {@link Object#hashCode()} and {@link Object#equals} for computing
665 * the order and equality. First the hashCode is compared, if this is equal, objects are compared
666 * using {@link Object#equals}.
667 *
668 * @return An order instance that is based on {@link Object#hashCode()} and {@link Object#equals}.
669 */
670 public static <A> Ord<A> hashEqualsOrd() {
671 return Ord.<A> ord(new F<A, F<A, Ordering>>() {
672 @Override
673 public F<A, Ordering> f(final A a) {
674 return new F<A, Ordering>() {
675 @Override
676 public Ordering f(final A a2) {
677 final int x = a.hashCode() - a2.hashCode();
678 return x < 0 ? Ordering.LT : x == 0 && a.equals(a2) ? Ordering.EQ : Ordering.GT;
679 }
680 };
681 }
682 });
683 }
684
685 }