1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.util.data;
23
24 import static java.lang.StrictMath.min;
25 import static java.util.Arrays.asList;
26 import static org.opencastproject.util.data.Collections.appendTo;
27 import static org.opencastproject.util.data.Collections.appendToA;
28 import static org.opencastproject.util.data.Collections.appendToM;
29 import static org.opencastproject.util.data.Collections.forc;
30 import static org.opencastproject.util.data.Collections.list;
31 import static org.opencastproject.util.data.Collections.toList;
32 import static org.opencastproject.util.data.Option.none;
33 import static org.opencastproject.util.data.Option.some;
34 import static org.opencastproject.util.data.Tuple.tuple;
35
36 import org.apache.commons.lang3.ArrayUtils;
37
38 import java.util.ArrayList;
39 import java.util.Collection;
40 import java.util.Comparator;
41 import java.util.Iterator;
42 import java.util.List;
43 import java.util.NoSuchElementException;
44
45 public final class Monadics {
46
47 private Monadics() {
48 }
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public abstract static class ListMonadic<A> implements Iterable<A> {
66
67 private ListMonadic() {
68 }
69
70
71 public final <B> ListMonadic<B> map(Function<? super A, ? extends B> f) {
72 return fmap(f);
73 }
74
75
76
77
78
79
80 public abstract <B> ListMonadic<B> fmap(Function<? super A, ? extends B> f);
81
82
83 public final <B> ListMonadic<B> flatMap(Function<? super A, ? extends Iterable<B>> f) {
84 return bind(f);
85 }
86
87
88
89
90
91 public abstract <B> ListMonadic<B> bind(Function<? super A, ? extends Iterable<B>> f);
92
93
94 public abstract <B> B foldl(B zero, Function2<? super B, ? super A, ? extends B> f);
95
96
97 public abstract A reducel(Function2<? super A, ? super A, ? extends A> f);
98
99
100 public abstract <M extends Iterable<A>> ListMonadic<A> concat(M m);
101
102
103 public abstract <X extends A> ListMonadic<A> cons(X a);
104
105
106 public abstract ListMonadic<A> filter(Function<? super A, Boolean> p);
107
108
109 public abstract Option<A> find(Function<? super A, Boolean> p);
110
111
112 public abstract boolean exists(Function<? super A, Boolean> p);
113
114
115 public abstract ListMonadic<A> each(Function<? super A, Void> e);
116
117 public abstract <B, M extends Iterable<B>> ListMonadic<Tuple<A, B>> zip(M bs);
118
119 public abstract ListMonadic<A> sort(Comparator<A> c);
120
121
122 public abstract Option<A> headOpt();
123
124
125 public abstract ListMonadic<A> take(int n);
126
127
128 public abstract ListMonadic<A> drop(int n);
129
130 public abstract String mkString(String sep);
131
132
133 public abstract List<A> value();
134 }
135
136
137 public abstract static class IteratorMonadic<A> implements Iterable<A> {
138
139 private IteratorMonadic() {
140 }
141
142
143 public final <B> IteratorMonadic<B> map(Function<A, B> f) {
144 return fmap(f);
145 }
146
147
148 public abstract <B> IteratorMonadic<B> fmap(Function<A, B> f);
149
150
151 public abstract <B> IteratorMonadic<B> mapIndex(Function2<A, Integer, B> f);
152
153
154 public final <B> IteratorMonadic<B> flatMap(Function<A, Iterator<B>> f) {
155 return bind(f);
156 }
157
158
159 public abstract <B> IteratorMonadic<B> bind(Function<A, Iterator<B>> f);
160
161
162
163
164
165
166
167
168
169
170
171
172 public abstract IteratorMonadic<A> filter(Function<A, Boolean> p);
173
174
175 public abstract boolean exists(Function<A, Boolean> p);
176
177
178 public abstract IteratorMonadic<A> take(int n);
179
180
181 public abstract IteratorMonadic<A> each(Function<A, Void> e);
182
183
184 public abstract IteratorMonadic<A> eachIndex(Function2<A, Integer, Void> e);
185
186
187 public abstract Iterator<A> value();
188
189
190 public abstract List<A> eval();
191 }
192
193 private static <A> List<A> newListBuilder() {
194 return new ArrayList<A>();
195 }
196
197 private static <A> List<A> newListBuilder(int size) {
198 return new ArrayList<A>(size);
199 }
200
201
202
203
204
205
206 public static <A> ListMonadic<A> mlist(final Collection<A> as) {
207 return mlist(new ArrayList<A>(as));
208 }
209
210
211 public static <A> ListMonadic<A> mlist(final List<A> as) {
212 return new ListMonadic<A>() {
213 @Override
214 public <B> ListMonadic<B> fmap(Function<? super A, ? extends B> f) {
215 final List<B> target = newListBuilder(as.size());
216 for (A a : as) target.add(f.apply(a));
217 return mlist(target);
218 }
219
220 @Override
221 public <B> ListMonadic<B> bind(Function<? super A, ? extends Iterable<B>> f) {
222 final List<B> target = newListBuilder();
223 for (A a : as)
224 appendTo(target, f.apply(a));
225 return mlist(target);
226 }
227
228 @Override
229 public ListMonadic<A> filter(Function<? super A, Boolean> p) {
230 final List<A> target = newListBuilder(as.size());
231 for (A a : as) {
232 if (p.apply(a)) {
233 target.add(a);
234 }
235 }
236 return mlist(target);
237 }
238
239 @Override
240 public Option<A> find(Function<? super A, Boolean> p) {
241 for (A a : as) {
242 if (p.apply(a))
243 return some(a);
244 }
245 return none();
246 }
247
248 @Override
249 public boolean exists(Function<? super A, Boolean> p) {
250 for (A a : as) {
251 if (p.apply(a))
252 return true;
253 }
254 return false;
255 }
256
257 @Override
258 public <B> B foldl(B zero, Function2<? super B, ? super A, ? extends B> f) {
259 B fold = zero;
260 for (A a : as) {
261 fold = f.apply(fold, a);
262 }
263 return fold;
264 }
265
266 @Override
267 public A reducel(Function2<? super A, ? super A, ? extends A> f) {
268 if (as.size() == 0) {
269 throw new RuntimeException("Cannot reduce an empty list");
270 } else {
271 A fold = as.get(0);
272 for (int i = 1; i < as.size(); i++) {
273 fold = f.apply(fold, as.get(i));
274 }
275 return fold;
276 }
277 }
278
279 @Override
280 public Option<A> headOpt() {
281 return !as.isEmpty() ? some(head()) : Option.<A> none();
282 }
283
284 private A head() {
285 return as.get(0);
286 }
287
288 @Override
289 public ListMonadic<A> take(int n) {
290 return mlist(as.subList(0, min(as.size(), n)));
291 }
292
293 @Override
294 public ListMonadic<A> drop(int n) {
295 return mlist(as.subList(min(as.size(), n), as.size()));
296 }
297
298 @Override
299 public <M extends Iterable<A>> ListMonadic<A> concat(M bs) {
300 return mlist(appendToM(Monadics.<A> newListBuilder(), as, bs));
301 }
302
303 @Override
304 public <X extends A> ListMonadic<A> cons(X a) {
305 return mlist(Collections.<A> cons(a, as));
306 }
307
308 @Override
309 public ListMonadic<A> each(Function<? super A, Void> e) {
310 for (A a : as)
311 e.apply(a);
312 return this;
313 }
314
315 @Override
316 public <B, M extends Iterable<B>> ListMonadic<Tuple<A, B>> zip(M m) {
317 final List<Tuple<A, B>> target = newListBuilder();
318 final Iterator<A> asi = as.iterator();
319 final Iterator<B> mi = m.iterator();
320 while (asi.hasNext() && mi.hasNext()) {
321 target.add(tuple(asi.next(), mi.next()));
322 }
323 return mlist(target);
324 }
325
326 @Override
327 public ListMonadic<A> sort(Comparator<A> c) {
328 final List<A> target = newListBuilder(as.size());
329 target.addAll(as);
330 java.util.Collections.sort(target, c);
331 return mlist(target);
332 }
333
334 @Override
335 public String mkString(String sep) {
336 return Collections.mkString(as, sep);
337 }
338
339 @Override
340 public Iterator<A> iterator() {
341 return as.iterator();
342 }
343
344 @Override
345 public List<A> value() {
346 return java.util.Collections.unmodifiableList(as);
347 }
348 };
349 }
350
351
352 public static <A> ListMonadic<A> mlist(final A... as) {
353 return new ListMonadic<A>() {
354 @Override
355 public <B> ListMonadic<B> fmap(Function<? super A, ? extends B> f) {
356 final List<B> target = newListBuilder(as.length);
357 for (A a : as)
358 target.add(f.apply(a));
359 return mlist(target);
360 }
361
362 @Override
363 public <B> ListMonadic<B> bind(Function<? super A, ? extends Iterable<B>> f) {
364 final List<B> target = newListBuilder();
365 for (A a : as)
366 appendTo(target, f.apply(a));
367 return mlist(target);
368 }
369
370 @Override
371 public ListMonadic<A> filter(Function<? super A, Boolean> p) {
372 List<A> target = newListBuilder(as.length);
373 for (A a : as) {
374 if (p.apply(a)) {
375 target.add(a);
376 }
377 }
378 return mlist(target);
379 }
380
381 @Override
382 public Option<A> find(Function<? super A, Boolean> p) {
383 for (A a : as) {
384 if (p.apply(a))
385 return some(a);
386 }
387 return none();
388 }
389
390 @Override
391 public boolean exists(Function<? super A, Boolean> p) {
392 for (A a : as) {
393 if (p.apply(a))
394 return true;
395 }
396 return false;
397 }
398
399 @Override
400 public <B> B foldl(B zero, Function2<? super B, ? super A, ? extends B> f) {
401 B fold = zero;
402 for (A a : as) {
403 fold = f.apply(fold, a);
404 }
405 return fold;
406 }
407
408 @Override
409 public A reducel(Function2<? super A, ? super A, ? extends A> f) {
410 if (as.length == 0) {
411 throw new RuntimeException("Cannot reduce an empty list");
412 } else {
413 A fold = as[0];
414 for (int i = 1; i < as.length; i++) {
415 fold = f.apply(fold, as[i]);
416 }
417 return fold;
418 }
419 }
420
421 @Override
422 public Option<A> headOpt() {
423 return as.length != 0 ? some(as[0]) : Option.<A> none();
424 }
425
426 @Override
427 public ListMonadic<A> take(int n) {
428 return (ListMonadic<A>) mlist(ArrayUtils.subarray(as, 0, n));
429 }
430
431 @Override
432 public ListMonadic<A> drop(int n) {
433 return (ListMonadic<A>) mlist(ArrayUtils.subarray(as, n, as.length));
434 }
435
436 @Override
437 public <M extends Iterable<A>> ListMonadic<A> concat(M bs) {
438 final List<A> t = newListBuilder(as.length);
439 return mlist(appendTo(appendToA(t, as), bs));
440 }
441
442 @Override
443 public <X extends A> ListMonadic<A> cons(X a) {
444 return mlist(Collections.<A, List> concat(Collections.<A> list(a), Collections.<A> list(as)));
445 }
446
447 @Override
448 public ListMonadic<A> each(Function<? super A, Void> e) {
449 for (A a : as) {
450 e.apply(a);
451 }
452 return mlist(as);
453 }
454
455 @Override
456 public <B, M extends Iterable<B>> ListMonadic<Tuple<A, B>> zip(M m) {
457 final List<Tuple<A, B>> target = newListBuilder();
458 int i = 0;
459 final Iterator<B> mi = m.iterator();
460 while (i < as.length && mi.hasNext()) {
461 target.add(tuple(as[i++], mi.next()));
462 }
463 return mlist(target);
464 }
465
466 @Override
467 public ListMonadic<A> sort(Comparator<A> c) {
468 final List<A> target = list(as);
469 java.util.Collections.sort(target, c);
470 return mlist(target);
471 }
472
473 @Override
474 public String mkString(String sep) {
475 return Arrays.mkString(as, sep);
476 }
477
478 @Override
479 public Iterator<A> iterator() {
480 return Collections.iterator(as);
481 }
482
483 @Override
484 public List<A> value() {
485 return asList(as);
486 }
487 };
488 }
489
490
491 public static <A> ListMonadic<A> mlist(final Iterator<A> as) {
492 return new ListMonadic<A>() {
493 @Override
494 public <B> ListMonadic<B> fmap(Function<? super A, ? extends B> f) {
495 final List<B> target = newListBuilder();
496 while (as.hasNext()) {
497 target.add(f.apply(as.next()));
498 }
499 return mlist(target);
500 }
501
502 @Override
503 public <B> ListMonadic<B> bind(Function<? super A, ? extends Iterable<B>> f) {
504 final List<B> target = newListBuilder();
505 while (as.hasNext())
506 appendTo(target, f.apply(as.next()));
507 return mlist(target);
508 }
509
510 @Override
511 public ListMonadic<A> filter(Function<? super A, Boolean> p) {
512 final List<A> target = newListBuilder();
513 while (as.hasNext()) {
514 A a = as.next();
515 if (p.apply(a)) {
516 target.add(a);
517 }
518 }
519 return mlist(target);
520 }
521
522 @Override
523 public Option<A> find(Function<? super A, Boolean> p) {
524 for (A a : forc(as)) {
525 if (p.apply(a))
526 return some(a);
527 }
528 return none();
529 }
530
531 @Override
532 public boolean exists(Function<? super A, Boolean> p) {
533 for (A a : forc(as)) {
534 if (p.apply(a))
535 return true;
536 }
537 return false;
538 }
539
540 @Override
541 public <B> B foldl(B zero, Function2<? super B, ? super A, ? extends B> f) {
542 B fold = zero;
543 while (as.hasNext()) {
544 fold = f.apply(fold, as.next());
545 }
546 return fold;
547 }
548
549 @Override
550 public A reducel(Function2<? super A, ? super A, ? extends A> f) {
551 if (!as.hasNext()) {
552 throw new RuntimeException("Cannot reduce an empty iterator");
553 } else {
554 A fold = as.next();
555 while (as.hasNext()) {
556 fold = f.apply(fold, as.next());
557 }
558 return fold;
559 }
560 }
561
562 @Override
563 public Option<A> headOpt() {
564 throw new UnsupportedOperationException();
565 }
566
567 @Override
568 public ListMonadic<A> take(final int n) {
569 return mlist(new Iter<A>() {
570 private int count = 0;
571
572 @Override
573 public boolean hasNext() {
574 return count < n && as.hasNext();
575 }
576
577 @Override
578 public A next() {
579 if (count < n) {
580 count++;
581 return as.next();
582 } else {
583 throw new NoSuchElementException();
584 }
585 }
586 });
587 }
588
589 @Override
590 public ListMonadic<A> drop(int n) {
591 int count = n;
592 while (as.hasNext() && count > 0) {
593 as.next();
594 count--;
595 }
596 return mlist(as);
597 }
598
599 @Override
600 public <M extends Iterable<A>> ListMonadic<A> concat(M bs) {
601 throw new UnsupportedOperationException();
602 }
603
604 @Override
605 public <X extends A> ListMonadic<A> cons(X a) {
606 return null;
607 }
608
609 @Override
610 public ListMonadic<A> each(Function<? super A, Void> e) {
611 while (as.hasNext()) e.apply(as.next());
612 return this;
613 }
614
615 @Override
616 public <B, M extends Iterable<B>> ListMonadic<Tuple<A, B>> zip(M m) {
617 final List<Tuple<A, B>> target = newListBuilder();
618 final Iterator<B> mi = m.iterator();
619 while (as.hasNext() && mi.hasNext()) {
620 target.add(tuple(as.next(), mi.next()));
621 }
622 return mlist(target);
623 }
624
625 @Override
626 public Iterator<A> iterator() {
627 return as;
628 }
629
630 @Override
631 public ListMonadic<A> sort(Comparator<A> c) {
632 throw new UnsupportedOperationException();
633 }
634
635 @Override
636 public String mkString(String sep) {
637 return Collections.mkString(toList(as), sep);
638 }
639
640 @Override
641 public List<A> value() {
642 return java.util.Collections.unmodifiableList(toList(as));
643 }
644 };
645 }
646
647
648 public static <A> IteratorMonadic<A> mlazy(final Iterator<A> as) {
649 return new IteratorMonadic<A>() {
650 @Override
651 public <B> IteratorMonadic<B> fmap(final Function<A, B> f) {
652 return mlazy(new Iter<B>() {
653 @Override
654 public boolean hasNext() {
655 return as.hasNext();
656 }
657
658 @Override
659 public B next() {
660 return f.apply(as.next());
661 }
662 });
663 }
664
665 @Override
666 public <B> IteratorMonadic<B> mapIndex(final Function2<A, Integer, B> f) {
667 return mlazy(new Iter<B>() {
668 private int i = 0;
669
670 @Override
671 public boolean hasNext() {
672 return as.hasNext();
673 }
674
675 @Override
676 public B next() {
677 return f.apply(as.next(), i++);
678 }
679 });
680 }
681
682 @Override
683 public <B> IteratorMonadic<B> bind(final Function<A, Iterator<B>> f) {
684 return mlazy(new Iter<B>() {
685 @Override
686 public boolean hasNext() {
687 return step.hasNext() || step().hasNext();
688 }
689
690 @Override
691 public B next() {
692 if (step.hasNext()) {
693 return step.next();
694 } else {
695 return step().next();
696 }
697 }
698
699
700 private Iterator<B> step = Monadics.emptyIter();
701
702 private Iterator<B> step() {
703 while (!step.hasNext() && as.hasNext()) {
704 step = f.apply(as.next());
705 }
706 return step;
707 }
708 });
709 }
710
711 @Override
712 public boolean exists(Function<A, Boolean> p) {
713 for (A a : forc(as)) {
714 if (p.apply(a))
715 return true;
716 }
717 return false;
718 }
719
720 @Override
721 public IteratorMonadic<A> filter(final Function<A, Boolean> p) {
722 return mlazy(new Iter<A>() {
723 private A next = null;
724
725 @Override
726 public boolean hasNext() {
727 if (next != null) {
728 return true;
729 } else {
730 for (A a : forc(as)) {
731 if (p.apply(a)) {
732 next = a;
733 return true;
734 }
735 }
736 return false;
737 }
738 }
739
740 @Override
741 public A next() {
742 try {
743 if (next != null || hasNext()) {
744 return next;
745 } else {
746 throw new NoSuchElementException();
747 }
748 } finally {
749 next = null;
750 }
751 }
752 });
753 }
754
755 @Override
756 public IteratorMonadic<A> take(final int n) {
757 return mlazy(new Iter<A>() {
758 private int count = 0;
759
760 @Override
761 public boolean hasNext() {
762 return count < n && as.hasNext();
763 }
764
765 @Override
766 public A next() {
767 if (count < n) {
768 count++;
769 return as.next();
770 } else {
771 throw new NoSuchElementException();
772 }
773 }
774 });
775 }
776
777 @Override
778 public IteratorMonadic<A> each(final Function<A, Void> e) {
779 return mlazy(new Iter<A>() {
780 @Override
781 public boolean hasNext() {
782 return as.hasNext();
783 }
784
785 @Override
786 public A next() {
787 final A a = as.next();
788 e.apply(a);
789 return a;
790 }
791 });
792 }
793
794 @Override
795 public IteratorMonadic<A> eachIndex(final Function2<A, Integer, Void> e) {
796 return mlazy(new Iter<A>() {
797 private int i = 0;
798
799 @Override
800 public boolean hasNext() {
801 return as.hasNext();
802 }
803
804 @Override
805 public A next() {
806 final A a = as.next();
807 e.apply(a, i++);
808 return a;
809 }
810 });
811 }
812
813 @Override
814 public Iterator<A> iterator() {
815 return as;
816 }
817
818 @Override
819 public Iterator<A> value() {
820 return as;
821 }
822
823 @Override
824 public List<A> eval() {
825 return toList(as);
826 }
827 };
828 }
829
830
831 public static <A> IteratorMonadic<A> mlazy(final List<A> as) {
832 return mlazy(as.iterator());
833 }
834
835 private abstract static class Iter<A> implements Iterator<A> {
836 @Override
837 public final void remove() {
838 throw new UnsupportedOperationException();
839 }
840 }
841
842 private static <A> Iterator<A> emptyIter() {
843 return new Iter<A>() {
844 @Override
845 public boolean hasNext() {
846 return false;
847 }
848
849 @Override
850 public A next() {
851 throw new NoSuchElementException();
852 }
853 };
854 }
855 }