View Javadoc

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