View Javadoc
1   package io.atlassian.fugue.optic;
2   
3   import io.atlassian.fugue.Either;
4   import io.atlassian.fugue.Iterables;
5   import io.atlassian.fugue.Monoid;
6   import io.atlassian.fugue.Option;
7   import io.atlassian.fugue.Pair;
8   import io.atlassian.fugue.Suppliers;
9   
10  import java.util.function.Function;
11  import java.util.function.Supplier;
12  
13  /**
14   * A {@link PIso} defines an isomorphism between types S, A and B, T:
15   * 
16   * <pre>
17   *              get                           reverse.get
18   *     --------------------&gt;             --------------------&gt;
19   *   S                       A         T                       B
20   *     &lt;--------------------             &lt;--------------------
21   *       reverse.reverseGet                   reverseGet
22   * </pre>
23   * <p>
24   * In addition, if f and g forms an isomorphism between `A` and `B`, i.e. if `f
25   * . g = id` and `g . f = id`, then a {@link PIso} defines an isomorphism
26   * between `S` and `T`:
27   * 
28   * <pre>
29   *     S           T                                   S           T
30   *     |           ↑                                   ↑           |
31   *     |           |                                   |           |
32   * get |           | reverseGet     reverse.reverseGet |           | reverse.get
33   *     |           |                                   |           |
34   *     ↓     f     |                                   |     g     ↓
35   *     A --------&gt; B                                   A &lt;-------- B
36   * </pre>
37   * <p>
38   * A {@link PIso} is also a valid {@link Getter}, {@link Fold}, {@link PLens},
39   * {@link PPrism}, {@link POptional}, {@link PTraversal} and {@link PSetter}
40   *
41   * @param <S> the source of a {@link PIso}
42   * @param <T> the modified source of a {@link PIso}
43   * @param <A> the target of a {@link PIso}
44   * @param <B> the modified target of a {@link PIso}
45   */
46  public abstract class PIso<S, T, A, B> {
47  
48    PIso() {
49      super();
50    }
51  
52    /**
53     * get the target of a {@link PIso}
54     */
55    public abstract A get(S s);
56  
57    /**
58     * get the modified source of a {@link PIso}
59     */
60    public abstract T reverseGet(B b);
61  
62    /**
63     * reverse a {@link PIso}: the source becomes the target and the target
64     * becomes the source
65     */
66    public abstract PIso<B, A, T, S> reverse();
67  
68    /**
69     * modify polymorphically the target of a {@link PIso} with an Applicative
70     * function
71     */
72    public final <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
73      return s -> f.apply(get(s)).andThen(this::reverseGet);
74    }
75  
76    /**
77     * modify polymorphically the target of a {@link PIso} with an Applicative
78     * function
79     */
80    public final <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
81      return s -> f.apply(get(s)).right().map(this::reverseGet);
82    }
83  
84    /**
85     * modify polymorphically the target of a {@link PIso} with an Applicative
86     * function
87     */
88    public final Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
89      return s -> f.apply(get(s)).map(this::reverseGet);
90    }
91  
92    /**
93     * modify polymorphically the target of a {@link PIso} with an Applicative
94     * function
95     */
96    public final Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
97      return s -> Iterables.map(f.apply(get(s)), this::reverseGet);
98    }
99  
100   /**
101    * modify polymorphically the target of a {@link PIso} with an Applicative
102    * function
103    */
104   public final Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
105     return s -> Suppliers.compose(this::reverseGet, f.apply(get(s)));
106   }
107 
108   /**
109    * modify polymorphically the target of a {@link PIso} with an Applicative
110    * function
111    */
112   public final Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
113     return s -> Pair.map(f.apply(get(s)), this::reverseGet);
114   }
115 
116   /**
117    * modify polymorphically the target of a {@link PIso} with a function
118    */
119   public final Function<S, T> modify(final Function<A, B> f) {
120     return s -> reverseGet(f.apply(get(s)));
121   }
122 
123   /**
124    * set polymorphically the target of a {@link PIso} with a value
125    */
126   public final Function<S, T> set(final B b) {
127     return __ -> reverseGet(b);
128   }
129 
130   /**
131    * pair two disjoint {@link PIso}
132    */
133   public <S1, T1, A1, B1> PIso<Pair<S, S1>, Pair<T, T1>, Pair<A, A1>, Pair<B, B1>> product(final PIso<S1, T1, A1, B1> other) {
134     return pIso(ss1 -> Pair.pair(get(ss1.left()), other.get(ss1.right())), bb1 -> Pair.pair(reverseGet(bb1.left()), other.reverseGet(bb1.right())));
135   }
136 
137   public <C> PIso<Pair<S, C>, Pair<T, C>, Pair<A, C>, Pair<B, C>> first() {
138     return pIso(sc -> Pair.pair(get(sc.left()), sc.right()), bc -> Pair.pair(reverseGet(bc.left()), bc.right()));
139   }
140 
141   public <C> PIso<Pair<C, S>, Pair<C, T>, Pair<C, A>, Pair<C, B>> second() {
142     return pIso(cs -> Pair.pair(cs.left(), get(cs.right())), cb -> Pair.pair(cb.left(), reverseGet(cb.right())));
143   }
144 
145   /**********************************************************/
146   /** Compose methods between a {@link PIso} and another Optics */
147   /**********************************************************/
148 
149   /**
150    * compose a {@link PIso} with a {@link Fold}
151    */
152   public final <C> Fold<S, C> composeFold(final Fold<A, C> other) {
153     return asFold().composeFold(other);
154   }
155 
156   /**
157    * compose a {@link PIso} with a {@link Getter}
158    */
159   public final <C> Getter<S, C> composeGetter(final Getter<A, C> other) {
160     return asGetter().composeGetter(other);
161   }
162 
163   /**
164    * compose a {@link PIso} with a {@link PSetter}
165    */
166   public final <C, D> PSetter<S, T, C, D> composeSetter(final PSetter<A, B, C, D> other) {
167     return asSetter().composeSetter(other);
168   }
169 
170   /**
171    * compose a {@link PIso} with a {@link PTraversal}
172    */
173   public final <C, D> PTraversal<S, T, C, D> composeTraversal(final PTraversal<A, B, C, D> other) {
174     return asTraversal().composeTraversal(other);
175   }
176 
177   /**
178    * compose a {@link PIso} with a {@link POptional}
179    */
180   public final <C, D> POptional<S, T, C, D> composeOptional(final POptional<A, B, C, D> other) {
181     return asOptional().composeOptional(other);
182   }
183 
184   /**
185    * compose a {@link PIso} with a {@link PPrism}
186    */
187   public final <C, D> PPrism<S, T, C, D> composePrism(final PPrism<A, B, C, D> other) {
188     return asPrism().composePrism(other);
189   }
190 
191   /**
192    * compose a {@link PIso} with a {@link PLens}
193    */
194   public final <C, D> PLens<S, T, C, D> composeLens(final PLens<A, B, C, D> other) {
195     return asLens().composeLens(other);
196   }
197 
198   /**
199    * compose a {@link PIso} with a {@link PIso}
200    */
201   public final <C, D> PIso<S, T, C, D> composeIso(final PIso<A, B, C, D> other) {
202     final PIso<S, T, A, B> self = this;
203     return new PIso<S, T, C, D>() {
204       @Override public C get(final S s) {
205         return other.get(self.get(s));
206       }
207 
208       @Override public T reverseGet(final D d) {
209         return self.reverseGet(other.reverseGet(d));
210       }
211 
212       @Override public PIso<D, C, T, S> reverse() {
213         final PIso<S, T, C, D> composeSelf = this;
214         return new PIso<D, C, T, S>() {
215           @Override public T get(final D d) {
216             return self.reverseGet(other.reverseGet(d));
217           }
218 
219           @Override public C reverseGet(final S s) {
220             return other.get(self.get(s));
221           }
222 
223           @Override public PIso<S, T, C, D> reverse() {
224             return composeSelf;
225           }
226         };
227       }
228     };
229   }
230 
231   /****************************************************************/
232   /** Transformation methods to view a {@link PIso} as another Optics */
233   /****************************************************************/
234 
235   /**
236    * view a {@link PIso} as a {@link Fold}
237    */
238   public final Fold<S, A> asFold() {
239     return new Fold<S, A>() {
240       @Override public <M> Function<S, M> foldMap(final Monoid<M> monoid, final Function<A, M> f) {
241         return s -> f.apply(PIso.this.get(s));
242       }
243     };
244   }
245 
246   /**
247    * view a {@link PIso} as a {@link Getter}
248    */
249   public final Getter<S, A> asGetter() {
250     return new Getter<S, A>() {
251       @Override public A get(final S s) {
252         return PIso.this.get(s);
253       }
254     };
255   }
256 
257   /**
258    * view a {@link PIso} as a {@link Setter}
259    */
260   public PSetter<S, T, A, B> asSetter() {
261     return new PSetter<S, T, A, B>() {
262       @Override public Function<S, T> modify(final Function<A, B> f) {
263         return PIso.this.modify(f);
264       }
265 
266       @Override public Function<S, T> set(final B b) {
267         return PIso.this.set(b);
268       }
269     };
270   }
271 
272   /**
273    * view a {@link PIso} as a {@link PTraversal}
274    */
275   public PTraversal<S, T, A, B> asTraversal() {
276     final PIso<S, T, A, B> self = this;
277     return new PTraversal<S, T, A, B>() {
278 
279       @Override public <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
280         return self.modifyFunctionF(f);
281       }
282 
283       @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
284         return self.modifyEitherF(f);
285       }
286 
287       @Override public Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
288         return self.modifyOptionF(f);
289       }
290 
291       @Override public Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
292         return self.modifyIterableF(f);
293       }
294 
295       @Override public Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
296         return self.modifySupplierF(f);
297       }
298 
299       @Override public Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
300         return self.modifyPairF(f);
301       }
302 
303       @Override public <M> Function<S, M> foldMap(final Monoid<M> monoid, final Function<A, M> f) {
304         return s -> f.apply(self.get(s));
305       }
306 
307     };
308   }
309 
310   /**
311    * view a {@link PIso} as a {@link POptional}
312    */
313   public POptional<S, T, A, B> asOptional() {
314     final PIso<S, T, A, B> self = this;
315     return new POptional<S, T, A, B>() {
316       @Override public Either<T, A> getOrModify(final S s) {
317         return Either.right(self.get(s));
318       }
319 
320       @Override public <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
321         return self.modifyFunctionF(f);
322       }
323 
324       @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
325         return self.modifyEitherF(f);
326       }
327 
328       @Override public Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
329         return self.modifyOptionF(f);
330       }
331 
332       @Override public Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
333         return self.modifyIterableF(f);
334       }
335 
336       @Override public Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
337         return self.modifySupplierF(f);
338       }
339 
340       @Override public Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
341         return self.modifyPairF(f);
342       }
343 
344       @Override public Function<S, T> set(final B b) {
345         return self.set(b);
346       }
347 
348       @Override public Option<A> getOption(final S s) {
349         return Option.some(self.get(s));
350       }
351 
352       @Override public Function<S, T> modify(final Function<A, B> f) {
353         return self.modify(f);
354       }
355     };
356   }
357 
358   /**
359    * view a {@link PIso} as a {@link PPrism}
360    */
361   public PPrism<S, T, A, B> asPrism() {
362     final PIso<S, T, A, B> self = this;
363     return new PPrism<S, T, A, B>() {
364       @Override public Either<T, A> getOrModify(final S s) {
365         return Either.right(self.get(s));
366       }
367 
368       @Override public T reverseGet(final B b) {
369         return self.reverseGet(b);
370       }
371 
372       @Override public Option<A> getOption(final S s) {
373         return Option.some(self.get(s));
374       }
375     };
376   }
377 
378   /**
379    * view a {@link PIso} as a {@link PLens}
380    */
381   public PLens<S, T, A, B> asLens() {
382     final PIso<S, T, A, B> self = this;
383     return new PLens<S, T, A, B>() {
384       @Override public A get(final S s) {
385         return self.get(s);
386       }
387 
388       @Override public Function<S, T> set(final B b) {
389         return self.set(b);
390       }
391 
392       @Override public Function<S, T> modify(final Function<A, B> f) {
393         return self.modify(f);
394       }
395 
396       @Override public <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
397         return self.modifyFunctionF(f);
398       }
399 
400       @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
401         return self.modifyEitherF(f);
402       }
403 
404       @Override public Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
405         return self.modifyOptionF(f);
406       }
407 
408       @Override public Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
409         return self.modifyIterableF(f);
410       }
411 
412       @Override public Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
413         return self.modifySupplierF(f);
414       }
415 
416       @Override public Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
417         return self.modifyPairF(f);
418       }
419 
420     };
421   }
422 
423   /**
424    * create a {@link PIso} using a pair of functions: one to get the target and
425    * one to get the source.
426    */
427   public static <S, T, A, B> PIso<S, T, A, B> pIso(final Function<S, A> get, final Function<B, T> reverseGet) {
428     return new PIso<S, T, A, B>() {
429 
430       @Override public A get(final S s) {
431         return get.apply(s);
432       }
433 
434       @Override public T reverseGet(final B b) {
435         return reverseGet.apply(b);
436       }
437 
438       @Override public PIso<B, A, T, S> reverse() {
439         final PIso<S, T, A, B> self = this;
440         return new PIso<B, A, T, S>() {
441           @Override public T get(final B b) {
442             return reverseGet.apply(b);
443           }
444 
445           @Override public A reverseGet(final S s) {
446             return get.apply(s);
447           }
448 
449           @Override public PIso<S, T, A, B> reverse() {
450             return self;
451           }
452         };
453       }
454 
455     };
456   }
457 
458   /**
459    * create a {@link PIso} between any type and itself. id is the zero element
460    * of optics composition, for all optics o of type O (e.g. Lens, Iso, Prism,
461    * ...):
462    * 
463    * <pre>
464    *  o composeIso Iso.id == o
465    *  Iso.id composeO o == o
466    * </pre>
467    * <p>
468    * (replace composeO by composeLens, composeIso, composePrism, ...)
469    */
470   public static <S, T> PIso<S, T, S, T> pId() {
471     return new PIso<S, T, S, T>() {
472 
473       @Override public S get(final S s) {
474         return s;
475       }
476 
477       @Override public T reverseGet(final T t) {
478         return t;
479       }
480 
481       @Override public PIso<T, S, T, S> reverse() {
482         final PIso<S, T, S, T> self = this;
483         return new PIso<T, S, T, S>() {
484           @Override public T get(final T t) {
485             return t;
486           }
487 
488           @Override public S reverseGet(final S s) {
489             return s;
490           }
491 
492           @Override public PIso<S, T, S, T> reverse() {
493             return self;
494           }
495         };
496       }
497     };
498   }
499 
500 }