1 package io.atlassian.fugue.optic;
2
3 import io.atlassian.fugue.Either;
4 import io.atlassian.fugue.Eithers;
5 import io.atlassian.fugue.Iterables;
6 import io.atlassian.fugue.Monoid;
7 import io.atlassian.fugue.Option;
8 import io.atlassian.fugue.Pair;
9 import io.atlassian.fugue.Suppliers;
10
11 import java.util.Collections;
12 import java.util.function.Function;
13 import java.util.function.Supplier;
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 public abstract class PPrism<S, T, A, B> {
38
39 PPrism() {
40 super();
41 }
42
43
44
45
46
47
48 public abstract Either<T, A> getOrModify(S s);
49
50
51
52
53 public abstract T reverseGet(B b);
54
55
56
57
58 public abstract Option<A> getOption(final S s);
59
60
61
62
63
64 public final <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
65 return s -> getOrModify(s).fold(t -> __ -> t, a -> f.apply(a).andThen(this::reverseGet));
66 }
67
68
69
70
71
72 public final <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
73 return s -> getOrModify(s).fold(Eithers.toRight(), t -> f.apply(t).right().map(this::reverseGet));
74 }
75
76
77
78
79
80 public final Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
81 return s -> getOrModify(s).fold(Option::some, t -> f.apply(t).map(this::reverseGet));
82 }
83
84
85
86
87
88 public final Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
89 return s -> getOrModify(s).fold(t -> Pair.pair(t, t), t -> Pair.map(f.apply(t), this::reverseGet));
90 }
91
92
93
94
95
96 public final Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
97 return s -> getOrModify(s).fold(Suppliers::ofInstance, t -> Suppliers.compose(this::reverseGet, f.apply(t)));
98 }
99
100
101
102
103
104 public final Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
105 return s -> getOrModify(s).fold(Collections::singleton, t -> Iterables.map(f.apply(t), this::reverseGet));
106 }
107
108
109
110
111 public final Function<S, T> modify(final Function<A, B> f) {
112 return s -> getOrModify(s).fold(Function.identity(), a -> reverseGet(f.apply(a)));
113 }
114
115
116
117
118
119 public final Function<S, Option<T>> modifyOption(final Function<A, B> f) {
120 return s -> getOption(s).map(a -> reverseGet(f.apply(a)));
121 }
122
123
124
125
126 public final Function<S, T> set(final B b) {
127 return modify(__ -> (b));
128 }
129
130
131
132
133
134 public final Function<S, Option<T>> setOption(final B b) {
135 return modifyOption(__ -> (b));
136 }
137
138
139
140
141 public final boolean isMatching(final S s) {
142 return getOption(s).isDefined();
143 }
144
145
146
147
148
149 public final Getter<B, T> re() {
150 return Getter.getter(this::reverseGet);
151 }
152
153
154
155
156
157
158
159
160 public final <C> Fold<S, C> composeFold(final Fold<A, C> other) {
161 return asFold().composeFold(other);
162 }
163
164
165
166
167 public final <C> Fold<S, C> composeGetter(final Getter<A, C> other) {
168 return asFold().composeGetter(other);
169 }
170
171
172
173
174 public final <C, D> PSetter<S, T, C, D> composeSetter(final PSetter<A, B, C, D> other) {
175 return asSetter().composeSetter(other);
176 }
177
178
179
180
181 public final <C, D> PTraversal<S, T, C, D> composeTraversal(final PTraversal<A, B, C, D> other) {
182 return asTraversal().composeTraversal(other);
183 }
184
185
186
187
188 public final <C, D> POptional<S, T, C, D> composeOptional(final POptional<A, B, C, D> other) {
189 return asOptional().composeOptional(other);
190 }
191
192
193
194
195 public final <C, D> POptional<S, T, C, D> composeLens(final PLens<A, B, C, D> other) {
196 return asOptional().composeOptional(other.asOptional());
197 }
198
199
200
201
202 public final <C, D> PPrism<S, T, C, D> composePrism(final PPrism<A, B, C, D> other) {
203 return new PPrism<S, T, C, D>() {
204
205 @Override public Either<T, C> getOrModify(final S s) {
206 return PPrism.this.getOrModify(s).right().flatMap(a -> other.getOrModify(a).bimap(b -> PPrism.this.set(b).apply(s), Function.identity()));
207 }
208
209 @Override public T reverseGet(final D d) {
210 return PPrism.this.reverseGet(other.reverseGet(d));
211 }
212
213 @Override public Option<C> getOption(final S s) {
214 return PPrism.this.getOption(s).flatMap(other::getOption);
215 }
216 };
217 }
218
219
220
221
222 public final <C, D> PPrism<S, T, C, D> composeIso(final PIso<A, B, C, D> other) {
223 return composePrism(other.asPrism());
224 }
225
226
227
228
229
230
231
232
233 public final Fold<S, A> asFold() {
234 return new Fold<S, A>() {
235 @Override public <M> Function<S, M> foldMap(final Monoid<M> monoid, final Function<A, M> f) {
236 return s -> getOption(s).map(f).getOrElse(monoid.zero());
237 }
238 };
239 }
240
241
242
243
244 public PSetter<S, T, A, B> asSetter() {
245 return new PSetter<S, T, A, B>() {
246 @Override public Function<S, T> modify(final Function<A, B> f) {
247 return PPrism.this.modify(f);
248 }
249
250 @Override public Function<S, T> set(final B b) {
251 return PPrism.this.set(b);
252 }
253 };
254 }
255
256
257
258
259 public PTraversal<S, T, A, B> asTraversal() {
260 final PPrism<S, T, A, B> self = this;
261 return new PTraversal<S, T, A, B>() {
262
263 @Override public <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
264 return self.modifyFunctionF(f);
265 }
266
267 @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
268 return self.modifyEitherF(f);
269 }
270
271 @Override public Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
272 return self.modifyOptionF(f);
273 }
274
275 @Override public Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
276 return self.modifyIterableF(f);
277 }
278
279 @Override public Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
280 return self.modifySupplierF(f);
281 }
282
283 @Override public Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
284 return self.modifyPairF(f);
285 }
286
287 @Override public <M> Function<S, M> foldMap(final Monoid<M> monoid, final Function<A, M> f) {
288 return s -> getOption(s).map(f).getOrElse(monoid.zero());
289 }
290
291 };
292 }
293
294
295
296
297 public POptional<S, T, A, B> asOptional() {
298 final PPrism<S, T, A, B> self = this;
299 return new POptional<S, T, A, B>() {
300
301 @Override public Either<T, A> getOrModify(final S s) {
302 return self.getOrModify(s);
303 }
304
305 @Override public <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
306 return self.modifyFunctionF(f);
307 }
308
309 @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
310 return self.modifyEitherF(f);
311 }
312
313 @Override public Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
314 return self.modifyOptionF(f);
315 }
316
317 @Override public Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
318 return self.modifyIterableF(f);
319 }
320
321 @Override public Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
322 return self.modifySupplierF(f);
323 }
324
325 @Override public Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
326 return self.modifyPairF(f);
327 }
328
329 @Override public Function<S, T> set(final B b) {
330 return self.set(b);
331 }
332
333 @Override public Option<A> getOption(final S s) {
334 return self.getOption(s);
335 }
336
337 @Override public Function<S, T> modify(final Function<A, B> f) {
338 return self.modify(f);
339 }
340
341 };
342 }
343
344 public static <S, T> PPrism<S, T, S, T> pId() {
345 return PIso.<S, T> pId().asPrism();
346 }
347
348
349
350
351
352 public static <S, T, A, B> PPrism<S, T, A, B> pPrism(final Function<S, Either<T, A>> getOrModify, final Function<B, T> reverseGet) {
353 return new PPrism<S, T, A, B>() {
354
355 @Override public Either<T, A> getOrModify(final S s) {
356 return getOrModify.apply(s);
357 }
358
359 @Override public T reverseGet(final B b) {
360 return reverseGet.apply(b);
361 }
362
363 @Override public Option<A> getOption(final S s) {
364 return getOrModify.apply(s).right().toOption();
365 }
366 };
367 }
368
369 }