View Javadoc

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