View Javadoc
1   package io.atlassian.fugue.optic;
2   
3   import io.atlassian.fugue.Either;
4   import io.atlassian.fugue.Eithers;
5   import io.atlassian.fugue.Functions;
6   import io.atlassian.fugue.Iterables;
7   import io.atlassian.fugue.Monoid;
8   import io.atlassian.fugue.Monoids;
9   import io.atlassian.fugue.Option;
10  import io.atlassian.fugue.Options;
11  import io.atlassian.fugue.Pair;
12  import io.atlassian.fugue.Suppliers;
13  
14  import java.util.Collections;
15  import java.util.function.BiFunction;
16  import java.util.function.Function;
17  import java.util.function.Predicate;
18  import java.util.function.Supplier;
19  
20  /**
21   * A {@link PTraversal} can be seen as a {@link POptional} generalised to 0 to n
22   * targets where n can be infinite.
23   * <p>
24   * {@link PTraversal} stands for Polymorphic Traversal as it set and modify
25   * methods change a type `A` to `B` and `S` to `T`. {@link Traversal} is a
26   * {@link PTraversal} restricted to monomorphic updates.
27   *
28   * @param <S> the source of a {@link PTraversal}
29   * @param <T> the modified source of a {@link PTraversal}
30   * @param <A> the target of a {@link PTraversal}
31   * @param <B> the modified target of a {@link PTraversal}
32   */
33  public abstract class PTraversal<S, T, A, B> {
34  
35    /**
36     * modify polymorphically the target of a {@link PTraversal} with an
37     * Applicative function
38     */
39    public abstract <C> Function<S, Function<C, T>> modifyFunctionF(Function<A, Function<C, B>> f);
40  
41    /**
42     * modify polymorphically the target of a {@link PTraversal} with an
43     * Applicative function
44     */
45    public abstract <L> Function<S, Either<L, T>> modifyEitherF(Function<A, Either<L, B>> f);
46  
47    /**
48     * modify polymorphically the target of a {@link PTraversal} with an
49     * Applicative function
50     */
51    public abstract Function<S, Option<T>> modifyOptionF(Function<A, Option<B>> f);
52  
53    /**
54     * modify polymorphically the target of a {@link PTraversal} with an
55     * Applicative function
56     */
57    public abstract Function<S, Iterable<T>> modifyIterableF(Function<A, Iterable<B>> f);
58  
59    /**
60     * modify polymorphically the target of a {@link PTraversal} with an
61     * Applicative function
62     */
63    public abstract Function<S, Supplier<T>> modifySupplierF(Function<A, Supplier<B>> f);
64  
65    /**
66     * modify polymorphically the target of a {@link PTraversal} with an
67     * Applicative function
68     */
69    public abstract Function<S, Pair<T, T>> modifyPairF(Function<A, Pair<B, B>> f);
70  
71    /**
72     * map each target to a {@link Monoid} and combine the results
73     */
74    public abstract <M> Function<S, M> foldMap(Monoid<M> monoid, Function<A, M> f);
75  
76    /**
77     * combine all targets using a target's {@link Monoid}
78     */
79    public final Function<S, A> fold(final Monoid<A> monoid) {
80      return foldMap(monoid, Function.identity());
81    }
82  
83    /**
84     * get all the targets of a {@link PTraversal}
85     */
86    public final Iterable<A> getAll(final S s) {
87      return foldMap(Monoids.iterable(), Collections::singleton).apply(s);
88    }
89  
90    /**
91     * find the first target of a {@link PTraversal} matching the predicate
92     */
93    public final Function<S, Option<A>> find(final Predicate<A> p) {
94      return foldMap(Monoids.firstOption(), a -> p.test(a) ? Option.some(a) : Option.none());
95    }
96  
97    /**
98     * get the first target of a {@link PTraversal}
99     */
100   public final Option<A> headOption(final S s) {
101     return find(__ -> (Boolean.TRUE)).apply(s);
102   }
103 
104   /**
105    * check if at least one target satisfies the predicate
106    */
107   public final Predicate<S> exist(final Predicate<A> p) {
108     return foldMap(Monoids.disjunction, p::test)::apply;
109   }
110 
111   /**
112    * check if all targets satisfy the predicate
113    */
114   public final Predicate<S> all(final Predicate<A> p) {
115     return foldMap(Monoids.conjunction, p::test)::apply;
116   }
117 
118   /**
119    * modify polymorphically the target of a {@link PTraversal} with a function
120    */
121   public final Function<S, T> modify(final Function<A, B> f) {
122     return s -> this.modifySupplierF(a -> Suppliers.ofInstance(f.apply(a))).apply(s).get();
123   }
124 
125   /**
126    * set polymorphically the target of a {@link PTraversal} with a value
127    */
128   public final Function<S, T> set(final B b) {
129     return modify(__ -> (b));
130   }
131 
132   /**
133    * join two {@link PTraversal} with the same target
134    */
135   public final <S1, T1> PTraversal<Either<S, S1>, Either<T, T1>, A, B> sum(final PTraversal<S1, T1, A, B> other) {
136     final PTraversal<S, T, A, B> self = this;
137     return new PTraversal<Either<S, S1>, Either<T, T1>, A, B>() {
138 
139       @Override public <C> Function<Either<S, S1>, Function<C, Either<T, T1>>> modifyFunctionF(final Function<A, Function<C, B>> f) {
140         return ss1 -> ss1.fold(s -> self.modifyFunctionF(f).apply(s).andThen(Eithers.toLeft()),
141           s1 -> other.modifyFunctionF(f).apply(s1).andThen(Eithers.toRight()));
142       }
143 
144       @Override public <L> Function<Either<S, S1>, Either<L, Either<T, T1>>> modifyEitherF(final Function<A, Either<L, B>> f) {
145         return ss1 -> ss1.fold(s -> self.modifyEitherF(f).apply(s).right().map(Eithers.toLeft()),
146           s1 -> other.modifyEitherF(f).apply(s1).right().map(Eithers.toRight()));
147       }
148 
149       @Override public Function<Either<S, S1>, Option<Either<T, T1>>> modifyOptionF(final Function<A, Option<B>> f) {
150         return ss1 -> ss1.fold(s -> self.modifyOptionF(f).apply(s).map(Eithers.toLeft()),
151           s1 -> other.modifyOptionF(f).apply(s1).map(Eithers.toRight()));
152       }
153 
154       @Override public Function<Either<S, S1>, Iterable<Either<T, T1>>> modifyIterableF(final Function<A, Iterable<B>> f) {
155         return ss1 -> ss1.fold(s -> Iterables.map(self.modifyIterableF(f).apply(s), Eithers.toLeft()),
156           s1 -> Iterables.map(other.modifyIterableF(f).apply(s1), Eithers.toRight()));
157       }
158 
159       @Override public Function<Either<S, S1>, Supplier<Either<T, T1>>> modifySupplierF(final Function<A, Supplier<B>> f) {
160         return ss1 -> ss1.fold(s -> Suppliers.compose(Eithers.toLeft(), self.modifySupplierF(f).apply(s)),
161           s1 -> Suppliers.compose(Eithers.toRight(), other.modifySupplierF(f).apply(s1)));
162       }
163 
164       @Override public Function<Either<S, S1>, Pair<Either<T, T1>, Either<T, T1>>> modifyPairF(final Function<A, Pair<B, B>> f) {
165         return ss1 -> ss1.fold(s -> Pair.map(self.modifyPairF(f).apply(s), Eithers.toLeft()),
166           s1 -> Pair.map(other.modifyPairF(f).apply(s1), Eithers.toRight()));
167       }
168 
169       @Override public <M> Function<Either<S, S1>, M> foldMap(final Monoid<M> monoid, final Function<A, M> f) {
170         return ss1 -> ss1.fold(self.foldMap(monoid, f), other.foldMap(monoid, f));
171       }
172 
173     };
174   }
175 
176   /****************************************************************/
177   /** Compose methods between a {@link PTraversal} and another Optics */
178   /****************************************************************/
179 
180   /**
181    * compose a {@link PTraversal} with a {@link Fold}
182    */
183   public final <C> Fold<S, C> composeFold(final Fold<A, C> other) {
184     return asFold().composeFold(other);
185   }
186 
187   //
188 
189   /**
190    * compose a {@link PTraversal} with a {@link Getter}
191    */
192   public final <C> Fold<S, C> composeFold(final Getter<A, C> other) {
193     return asFold().composeGetter(other);
194   }
195 
196   /**
197    * compose a {@link PTraversal} with a {@link PSetter}
198    */
199   public final <C, D> PSetter<S, T, C, D> composeSetter(final PSetter<A, B, C, D> other) {
200     return asSetter().composeSetter(other);
201   }
202 
203   /**
204    * compose a {@link PTraversal} with a {@link PTraversal}
205    */
206   public final <C, D> PTraversal<S, T, C, D> composeTraversal(final PTraversal<A, B, C, D> other) {
207     final PTraversal<S, T, A, B> self = this;
208     return new PTraversal<S, T, C, D>() {
209 
210       @Override public <G> Function<S, Function<G, T>> modifyFunctionF(final Function<C, Function<G, D>> f) {
211         return self.modifyFunctionF(other.modifyFunctionF(f));
212       }
213 
214       @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<C, Either<L, D>> f) {
215         return self.modifyEitherF(other.modifyEitherF(f));
216       }
217 
218       @Override public Function<S, Option<T>> modifyOptionF(final Function<C, Option<D>> f) {
219         return self.modifyOptionF(other.modifyOptionF(f));
220       }
221 
222       @Override public Function<S, Iterable<T>> modifyIterableF(final Function<C, Iterable<D>> f) {
223         return self.modifyIterableF(other.modifyIterableF(f));
224       }
225 
226       @Override public Function<S, Supplier<T>> modifySupplierF(final Function<C, Supplier<D>> f) {
227         return self.modifySupplierF(other.modifySupplierF(f));
228       }
229 
230       @Override public Function<S, Pair<T, T>> modifyPairF(final Function<C, Pair<D, D>> f) {
231         return self.modifyPairF(other.modifyPairF(f));
232       }
233 
234       @Override public <M> Function<S, M> foldMap(final Monoid<M> monoid, final Function<C, M> f) {
235         return self.foldMap(monoid, other.foldMap(monoid, f));
236       }
237     };
238   }
239 
240   /**
241    * compose a {@link PTraversal} with a {@link POptional}
242    */
243   public final <C, D> PTraversal<S, T, C, D> composeOptional(final POptional<A, B, C, D> other) {
244     return composeTraversal(other.asTraversal());
245   }
246 
247   /**
248    * compose a {@link PTraversal} with a {@link PPrism}
249    */
250   public final <C, D> PTraversal<S, T, C, D> composePrism(final PPrism<A, B, C, D> other) {
251     return composeTraversal(other.asTraversal());
252   }
253 
254   /**
255    * compose a {@link PTraversal} with a {@link PLens}
256    */
257   public final <C, D> PTraversal<S, T, C, D> composeLens(final PLens<A, B, C, D> other) {
258     return composeTraversal(other.asTraversal());
259   }
260 
261   /**
262    * compose a {@link PTraversal} with a {@link PIso}
263    */
264   public final <C, D> PTraversal<S, T, C, D> composeIso(final PIso<A, B, C, D> other) {
265     return composeTraversal(other.asTraversal());
266   }
267 
268   /**********************************************************************/
269   /** Transformation methods to view a {@link PTraversal} as another Optics */
270   /**********************************************************************/
271 
272   /**
273    * view a {@link PTraversal} as a {@link Fold}
274    */
275   public final Fold<S, A> asFold() {
276     return new Fold<S, A>() {
277       @Override public <M> Function<S, M> foldMap(final Monoid<M> monoid, final Function<A, M> f) {
278         return PTraversal.this.foldMap(monoid, f);
279       }
280     };
281   }
282 
283   /**
284    * view a {@link PTraversal} as a {@link PSetter}
285    */
286   public PSetter<S, T, A, B> asSetter() {
287     return PSetter.pSetter(this::modify);
288   }
289 
290   public static <S, T> PTraversal<S, T, S, T> pId() {
291     return PIso.<S, T> pId().asTraversal();
292   }
293 
294   public static <S, T> PTraversal<Either<S, S>, Either<T, T>, S, T> pCodiagonal() {
295     return new PTraversal<Either<S, S>, Either<T, T>, S, T>() {
296 
297       @Override public <C> Function<Either<S, S>, Function<C, Either<T, T>>> modifyFunctionF(final Function<S, Function<C, T>> f) {
298         return s -> s.bimap(f, f).fold(f1 -> f1.andThen(Eithers.toLeft()), f1 -> f1.andThen(Eithers.toRight()));
299       }
300 
301       @Override public <L> Function<Either<S, S>, Either<L, Either<T, T>>> modifyEitherF(final Function<S, Either<L, T>> f) {
302         return s -> s.bimap(f, f).fold(e -> e.right().map(Eithers.toLeft()), e -> e.right().map(Eithers.toRight()));
303       }
304 
305       @Override public Function<Either<S, S>, Option<Either<T, T>>> modifyOptionF(final Function<S, Option<T>> f) {
306         return s -> s.bimap(f, f).fold(o -> o.map(Eithers.toLeft()), o -> o.map(Eithers.toRight()));
307       }
308 
309       @Override public Function<Either<S, S>, Iterable<Either<T, T>>> modifyIterableF(final Function<S, Iterable<T>> f) {
310         return s -> s.bimap(f, f).fold(ts -> Iterables.map(ts, Eithers.toLeft()), ts -> Iterables.map(ts, Eithers.toRight()));
311       }
312 
313       @Override public Function<Either<S, S>, Supplier<Either<T, T>>> modifySupplierF(final Function<S, Supplier<T>> f) {
314         return s -> s.bimap(f, f).fold(p1 -> Suppliers.compose(Eithers.toLeft(), p1), p1 -> Suppliers.compose(Eithers.toRight(), p1));
315       }
316 
317       @Override public Function<Either<S, S>, Pair<Either<T, T>, Either<T, T>>> modifyPairF(final Function<S, Pair<T, T>> f) {
318         return s -> s.bimap(f, f).fold(tt -> Pair.map(tt, Eithers.toLeft()), tt -> Pair.map(tt, Eithers.toRight()));
319       }
320 
321       @Override public <M> Function<Either<S, S>, M> foldMap(final Monoid<M> monoid, final Function<S, M> f) {
322         return s -> s.fold(f, f);
323       }
324     };
325   }
326 
327   public static <S, T, A, B> PTraversal<S, T, A, B> pTraversal(final Function<S, A> get1, final Function<S, A> get2,
328     final BiFunction<B, B, Function<S, T>> set) {
329     return new PTraversal<S, T, A, B>() {
330 
331       @Override public <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
332         return s -> Functions.ap(f.apply(get2.apply(s)), f.apply(get1.apply(s)).andThen(b1 -> b2 -> set.apply(b1, b2).apply(s)));
333       }
334 
335       @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
336         return s -> f.apply(get2.apply(s)).right().ap(f.apply(get1.apply(s)).right().<Function<B, T>> map(b1 -> b2 -> set.apply(b1, b2).apply(s)));
337       }
338 
339       @Override public Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
340         return s -> Options.ap(f.apply(get2.apply(s)), f.apply(get1.apply(s)).<Function<B, T>> map(b1 -> b2 -> set.apply(b1, b2).apply(s)));
341       }
342 
343       @Override public Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
344         return s -> Iterables.ap(f.apply(get2.apply(s)), Iterables.map(f.apply(get1.apply(s)), b1 -> b2 -> set.apply(b1, b2).apply(s)));
345       }
346 
347       @Override public Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
348         return s -> Suppliers.ap(f.apply(get2.apply(s)), Suppliers.compose(b1 -> b2 -> set.apply(b1, b2).apply(s), f.apply(get1.apply(s))));
349       }
350 
351       @Override public Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
352         return s -> Pair.ap(f.apply(get2.apply(s)), Pair.map(f.apply(get1.apply(s)), b1 -> b2 -> set.apply(b1, b2).apply(s)));
353       }
354 
355       @Override public <M> Function<S, M> foldMap(final Monoid<M> monoid, final Function<A, M> f) {
356         return s -> monoid.append(f.apply(get1.apply(s)), f.apply(get2.apply(s)));
357       }
358     };
359   }
360 
361   public static <S, T, A, B> PTraversal<S, T, A, B> pTraversal(final Function<S, A> get1, final Function<S, A> get2, final Function<S, A> get3,
362     final Function<B, Function<B, Function<B, Function<S, T>>>> set) {
363     return fromCurried(pTraversal(get1, get2, (b1, b2) -> s -> (b3 -> set.apply(b1).apply(b2).apply(b3).apply(s))), get3);
364   }
365 
366   public static <S, T, A, B> PTraversal<S, T, A, B> pTraversal(final Function<S, A> get1, final Function<S, A> get2, final Function<S, A> get3,
367     final Function<S, A> get4, final Function<B, Function<B, Function<B, Function<B, Function<S, T>>>>> set) {
368     return fromCurried(pTraversal(get1, get2, get3, b1 -> b2 -> b3 -> s -> b4 -> set.apply(b1).apply(b2).apply(b3).apply(b4).apply(s)), get4);
369   }
370 
371   public static <S, T, A, B> PTraversal<S, T, A, B> pTraversal(final Function<S, A> get1, final Function<S, A> get2, final Function<S, A> get3,
372     final Function<S, A> get4, final Function<S, A> get5, final Function<B, Function<B, Function<B, Function<B, Function<B, Function<S, T>>>>>> set) {
373     return fromCurried(
374       pTraversal(get1, get2, get3, get4, b1 -> b2 -> b3 -> b4 -> s -> b5 -> set.apply(b1).apply(b2).apply(b3).apply(b4).apply(b5).apply(s)), get5);
375   }
376 
377   public static <S, T, A, B> PTraversal<S, T, A, B> pTraversal(final Function<S, A> get1, final Function<S, A> get2, final Function<S, A> get3,
378     final Function<S, A> get4, final Function<S, A> get5, final Function<S, A> get6,
379     final Function<B, Function<B, Function<B, Function<B, Function<B, Function<B, Function<S, T>>>>>>> set) {
380     return fromCurried(
381       pTraversal(get1, get2, get3, get4, get5,
382         b1 -> b2 -> b3 -> b4 -> b5 -> s -> b6 -> set.apply(b1).apply(b2).apply(b3).apply(b4).apply(b5).apply(b6).apply(s)), get6);
383   }
384 
385   private static <S, T, A, B> PTraversal<S, T, A, B> fromCurried(final PTraversal<S, Function<B, T>, A, B> curriedTraversal,
386     final Function<S, A> lastGet) {
387     return new PTraversal<S, T, A, B>() {
388 
389       @Override public <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
390         return s -> Functions.ap(f.apply(lastGet.apply(s)), curriedTraversal.modifyFunctionF(f).apply(s));
391       }
392 
393       @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
394         return s -> f.apply(lastGet.apply(s)).right().ap(curriedTraversal.modifyEitherF(f).apply(s));
395       }
396 
397       @Override public Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
398         return s -> Options.ap(f.apply(lastGet.apply(s)), curriedTraversal.modifyOptionF(f).apply(s));
399       }
400 
401       @Override public Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
402         return s -> Iterables.ap(f.apply(lastGet.apply(s)), curriedTraversal.modifyIterableF(f).apply(s));
403       }
404 
405       @Override public Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
406         return s -> Suppliers.ap(f.apply(lastGet.apply(s)), curriedTraversal.modifySupplierF(f).apply(s));
407       }
408 
409       @Override public Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
410         return s -> Pair.ap(f.apply(lastGet.apply(s)), curriedTraversal.modifyPairF(f).apply(s));
411       }
412 
413       @Override public <M> Function<S, M> foldMap(final Monoid<M> monoid, final Function<A, M> f) {
414         return s -> monoid.append(curriedTraversal.foldMap(monoid, f).apply(s), f.apply(lastGet.apply(s)));
415       }
416     };
417   }
418 }