1 package io.atlassian.fugue.optic;
2
3 import io.atlassian.fugue.Either;
4 import io.atlassian.fugue.Monoid;
5 import io.atlassian.fugue.Monoids;
6 import io.atlassian.fugue.Option;
7
8 import java.util.Collections;
9 import java.util.function.Function;
10 import java.util.function.Predicate;
11
12
13
14
15
16
17
18
19
20
21
22
23 public abstract class Fold<S, A> {
24
25
26
27
28
29
30 public abstract <M> Function<S, M> foldMap(Monoid<M> monoid, Function<A, M> f);
31
32
33
34
35 public final Function<S, A> fold(Monoid<A> monoid) {
36 return foldMap(monoid, Function.identity());
37 }
38
39
40
41
42 public final Iterable<A> getAll(final S s) {
43 return foldMap(Monoids.iterable(), Collections::singleton).apply(s);
44 }
45
46
47
48
49 public final Function<S, Option<A>> find(final Predicate<A> p) {
50 return foldMap(Monoids.firstOption(), a -> p.test(a) ? Option.some(a) : Option.none());
51 }
52
53
54
55
56 public final Option<A> headOption(final S s) {
57 return find(__ -> true).apply(s);
58 }
59
60
61
62
63 public final Predicate<S> exist(final Predicate<A> p) {
64 return foldMap(Monoids.disjunction, p::test)::apply;
65 }
66
67
68
69
70 public final Function<S, Boolean> all(final Predicate<A> p) {
71 return foldMap(Monoids.conjunction, p::test)::apply;
72 }
73
74
75
76
77 public final <S1> Fold<Either<S, S1>, A> sum(final Fold<S1, A> other) {
78 return new Fold<Either<S, S1>, A>() {
79 @Override public <B> Function<Either<S, S1>, B> foldMap(final Monoid<B> monoid, final Function<A, B> f) {
80 return s -> s.fold(Fold.this.foldMap(monoid, f), other.foldMap(monoid, f));
81 }
82 };
83 }
84
85
86
87
88
89
90
91
92 public final <B> Fold<S, B> composeFold(final Fold<A, B> other) {
93 return new Fold<S, B>() {
94 @Override public <C> Function<S, C> foldMap(final Monoid<C> monoid, final Function<B, C> f) {
95 return Fold.this.foldMap(monoid, other.foldMap(monoid, f));
96 }
97 };
98 }
99
100
101
102
103 public final <C> Fold<S, C> composeGetter(final Getter<A, C> other) {
104 return composeFold(other.asFold());
105 }
106
107
108
109
110 public final <B, C, D> Fold<S, C> composeOptional(final POptional<A, B, C, D> other) {
111 return composeFold(other.asFold());
112 }
113
114
115
116
117 public final <B, C, D> Fold<S, C> composePrism(final PPrism<A, B, C, D> other) {
118 return composeFold(other.asFold());
119 }
120
121
122
123
124 public final <B, C, D> Fold<S, C> composeLens(final PLens<A, B, C, D> other) {
125 return composeFold(other.asFold());
126 }
127
128
129
130
131 public final <B, C, D> Fold<S, C> composeIso(final PIso<A, B, C, D> other) {
132 return composeFold(other.asFold());
133 }
134
135 public static <A> Fold<A, A> id() {
136 return PIso.<A, A> pId().asFold();
137 }
138
139 public static <A> Fold<Either<A, A>, A> codiagonal() {
140 return new Fold<Either<A, A>, A>() {
141 @Override public <B> Function<Either<A, A>, B> foldMap(final Monoid<B> monoid, final Function<A, B> f) {
142 return e -> e.fold(f, f);
143 }
144 };
145 }
146
147 }