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.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   * A {@link POptional} can be seen as a pair of functions: - `getOrModify: S
17   * => T \/ A` - `set : (B, S) => T`
18   * <p>
19   * A {@link POptional} could also be defined as a weaker {@link PLens} and
20   * weaker {@link PPrism}
21   * <p>
22   * {@link POptional} stands for Polymorphic Optional as it set and modify
23   * methods change a type `A` to `B` and `S` to `T`. {@link Optional} is a
24   * {@link POptional} restricted to monomorphic updates: {{{ type Optional[S, A]
25   * = POptional[S, S, A, A] }}}
26   *
27   * @param <S> the source of a {@link POptional}
28   * @param <T> the modified source of a {@link POptional}
29   * @param <A> the target of a {@link POptional}
30   * @param <B> the modified target of a {@link POptional}
31   */
32  public abstract class POptional<S, T, A, B> {
33  
34    POptional() {
35      super();
36    }
37  
38    /**
39     * get the target of a {@link POptional} or modify the source in case there is
40     * no target
41     */
42    public abstract Either<T, A> getOrModify(S s);
43  
44    /**
45     * get the modified source of a {@link POptional}
46     */
47    public abstract Function<S, T> set(final B b);
48  
49    /**
50     * get the target of a {@link POptional} or nothing if there is no target
51     */
52    public abstract Option<A> getOption(final S s);
53  
54    /**
55     * modify polymorphically the target of a {@link POptional} with an
56     * Applicative function
57     */
58    public abstract <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f);
59  
60    /**
61     * modify polymorphically the target of a {@link POptional} with an
62     * Applicative function
63     */
64    public abstract <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f);
65  
66    /**
67     * modify polymorphically the target of a {@link POptional} with an
68     * Applicative function
69     */
70    public abstract Function<S, Option<T>> modifyOptionF(Function<A, Option<B>> f);
71  
72    /**
73     * modify polymorphically the target of a {@link POptional} with an
74     * Applicative function
75     */
76    public abstract Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f);
77  
78    /**
79     * modify polymorphically the target of a {@link POptional} with an
80     * Applicative function
81     */
82    public abstract Function<S, Supplier<T>> modifySupplierF(Function<A, Supplier<B>> f);
83  
84    /**
85     * modify polymorphically the target of a {@link POptional} with an
86     * Applicative function
87     */
88    public abstract Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f);
89  
90    /**
91     * modify polymorphically the target of a {@link POptional} with a function
92     */
93    public abstract Function<S, T> modify(final Function<A, B> f);
94  
95    /**
96     * modify polymorphically the target of a {@link POptional} with a function.
97     * return empty if the {@link POptional} is not matching
98     */
99    public final Function<S, Option<T>> modifyOption(final Function<A, B> f) {
100     return s -> getOption(s).map(__ -> modify(f).apply(s));
101   }
102 
103   /**
104    * set polymorphically the target of a {@link POptional} with a value. return
105    * empty if the {@link POptional} is not matching
106    */
107   public final Function<S, Option<T>> setOption(final B b) {
108     return modifyOption(__ -> (b));
109   }
110 
111   /**
112    * check if a {@link POptional} has a target
113    */
114   public final boolean isMatching(final S s) {
115     return getOption(s).isDefined();
116 
117   }
118 
119   /**
120    * join two {@link POptional} with the same target
121    */
122   public final <S1, T1> POptional<Either<S, S1>, Either<T, T1>, A, B> sum(final POptional<S1, T1, A, B> other) {
123     return pOptional(e -> e.fold(s -> getOrModify(s).left().map(Eithers.toLeft()), s1 -> other.getOrModify(s1).left().map(Eithers.toRight())),
124       b -> e -> e.bimap(set(b), other.set(b)));
125   }
126 
127   public <C> POptional<Pair<S, C>, Pair<T, C>, Pair<A, C>, Pair<B, C>> first() {
128     return pOptional(sc -> getOrModify(sc.left()).bimap(t -> Pair.pair(t, sc.right()), a -> Pair.pair(a, sc.right())),
129       bc -> s_ -> Pair.pair(set(bc.left()).apply(s_.left()), bc.right()));
130   }
131 
132   public <C> POptional<Pair<C, S>, Pair<C, T>, Pair<C, A>, Pair<C, B>> second() {
133     return pOptional(cs -> getOrModify(cs.right()).bimap(t -> Pair.pair(cs.left(), t), a -> Pair.pair(cs.left(), a)),
134       cb -> _s -> Pair.pair(cb.left(), set(cb.right()).apply(_s.right())));
135   }
136 
137   /***************************************************************/
138   /** Compose methods between a {@link POptional} and another Optics */
139   /***************************************************************/
140 
141   /**
142    * compose a {@link POptional} with a {@link Fold}
143    */
144   public final <C> Fold<S, C> composeFold(final Fold<A, C> other) {
145     return asFold().composeFold(other);
146   }
147 
148   /**
149    * compose a {@link POptional} with a {@link Getter}
150    */
151   public final <C> Fold<S, C> composeGetter(final Getter<A, C> other) {
152     return asFold().composeGetter(other);
153   }
154 
155   /**
156    * compose a {@link POptional} with a {@link PSetter}
157    */
158   public final <C, D> PSetter<S, T, C, D> composeSetter(final PSetter<A, B, C, D> other) {
159     return asSetter().composeSetter(other);
160   }
161 
162   /**
163    * compose a {@link POptional} with a {@link PTraversal}
164    */
165   public final <C, D> PTraversal<S, T, C, D> composeTraversal(final PTraversal<A, B, C, D> other) {
166     return asTraversal().composeTraversal(other);
167   }
168 
169   /**
170    * compose a {@link POptional} with a {@link POptional}
171    */
172   public final <C, D> POptional<S, T, C, D> composeOptional(final POptional<A, B, C, D> other) {
173     final POptional<S, T, A, B> self = this;
174     return new POptional<S, T, C, D>() {
175 
176       @Override public Either<T, C> getOrModify(final S s) {
177         return self.getOrModify(s).right().flatMap(a -> other.getOrModify(a).bimap(b -> POptional.this.set(b).apply(s), Function.identity()));
178       }
179 
180       @Override public Function<S, T> set(final D d) {
181         return self.modify(other.set(d));
182       }
183 
184       @Override public Option<C> getOption(final S s) {
185         return self.getOption(s).flatMap(other::getOption);
186       }
187 
188       @Override public <G> Function<S, Function<G, T>> modifyFunctionF(final Function<C, Function<G, D>> f) {
189         return self.modifyFunctionF(other.modifyFunctionF(f));
190       }
191 
192       @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<C, Either<L, D>> f) {
193         return self.modifyEitherF(other.modifyEitherF(f));
194       }
195 
196       @Override public Function<S, Option<T>> modifyOptionF(final Function<C, Option<D>> f) {
197         return self.modifyOptionF(other.modifyOptionF(f));
198       }
199 
200       @Override public Function<S, Iterable<T>> modifyIterableF(final Function<C, Iterable<D>> f) {
201         return self.modifyIterableF(other.modifyIterableF(f));
202       }
203 
204       @Override public Function<S, Supplier<T>> modifySupplierF(final Function<C, Supplier<D>> f) {
205         return self.modifySupplierF(other.modifySupplierF(f));
206       }
207 
208       @Override public Function<S, Pair<T, T>> modifyPairF(final Function<C, Pair<D, D>> f) {
209         return self.modifyPairF(other.modifyPairF(f));
210       }
211 
212       @Override public Function<S, T> modify(final Function<C, D> f) {
213         return self.modify(other.modify(f));
214       }
215     };
216   }
217 
218   /**
219    * compose a {@link POptional} with a {@link PPrism}
220    */
221   public final <C, D> POptional<S, T, C, D> composePrism(final PPrism<A, B, C, D> other) {
222     return composeOptional(other.asOptional());
223   }
224 
225   /**
226    * compose a {@link POptional} with a {@link PLens}
227    */
228   public final <C, D> POptional<S, T, C, D> composeLens(final PLens<A, B, C, D> other) {
229     return composeOptional(other.asOptional());
230   }
231 
232   /**
233    * compose a {@link POptional} with a {@link PIso}
234    */
235   public final <C, D> POptional<S, T, C, D> composeIso(final PIso<A, B, C, D> other) {
236     return composeOptional(other.asOptional());
237   }
238 
239   /*********************************************************************/
240   /** Transformation methods to view a {@link POptional} as another Optics */
241   /*********************************************************************/
242 
243   /**
244    * view a {@link POptional} as a {@link Fold}
245    */
246   public final Fold<S, A> asFold() {
247     return new Fold<S, A>() {
248       @Override public <M> Function<S, M> foldMap(final Monoid<M> monoid, final Function<A, M> f) {
249         return s -> POptional.this.getOption(s).map(f).getOrElse(monoid.zero());
250       }
251     };
252   }
253 
254   /**
255    * view a {@link POptional} as a {@link PSetter}
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 POptional.this.modify(f);
261       }
262 
263       @Override public Function<S, T> set(final B b) {
264         return POptional.this.set(b);
265       }
266     };
267   }
268 
269   /**
270    * view a {@link POptional} as a {@link PTraversal}
271    */
272   public PTraversal<S, T, A, B> asTraversal() {
273     final POptional<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 -> self.getOption(s).map(f).getOrElse(monoid.zero());
302       }
303     };
304   }
305 
306   public static <S, T> POptional<S, T, S, T> pId() {
307     return PIso.<S, T> pId().asOptional();
308   }
309 
310   /**
311    * create a {@link POptional} using the canonical functions: getOrModify and
312    * set
313    */
314   public static <S, T, A, B> POptional<S, T, A, B> pOptional(final Function<S, Either<T, A>> getOrModify, final Function<B, Function<S, T>> set) {
315     return new POptional<S, T, A, B>() {
316       @Override public Either<T, A> getOrModify(final S s) {
317         return getOrModify.apply(s);
318       }
319 
320       @Override public Function<S, T> set(final B b) {
321         return set.apply(b);
322       }
323 
324       @Override public Option<A> getOption(final S s) {
325         return getOrModify.apply(s).right().toOption();
326       }
327 
328       @Override public <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
329         return s -> getOrModify.apply(s).fold(t -> __ -> t, a -> f.apply(a).andThen(b -> set.apply(b).apply(s)));
330       }
331 
332       @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
333         return s -> getOrModify.apply(s).fold(Eithers.toRight(), t -> f.apply(t).right().map(b -> set.apply(b).apply(s)));
334       }
335 
336       @Override public Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
337         return s -> getOrModify.apply(s).fold(Option::some, t -> f.apply(t).map(b -> set.apply(b).apply(s)));
338       }
339 
340       @Override public Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
341         return s -> getOrModify.apply(s).fold(Collections::singleton, t -> Iterables.<B, T> map(f.apply(t), b -> set.apply(b).apply(s)));
342       }
343 
344       @Override public Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
345         return s -> getOrModify.apply(s).fold(Suppliers::ofInstance, t -> Suppliers.<B, T> compose(b -> set.apply(b).apply(s), f.apply(t)));
346       }
347 
348       @Override public Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
349         return s -> getOrModify.apply(s).fold(t -> Pair.pair(t, t), t -> Pair.<B, T> map(f.apply(t), b -> set.apply(b).apply(s)));
350       }
351 
352       @Override public Function<S, T> modify(final Function<A, B> f) {
353         return s -> getOrModify.apply(s).fold(Function.identity(), a -> set.apply(f.apply(a)).apply(s));
354       }
355     };
356   }
357 }