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 PLens} can be seen as a pair of functions: - `get: S => A` i.e.
15   * from an `S`, we can extract an `A` - `set: (B, S) => T` i.e. if we replace
16   * an `A` by a `B` in an `S`, we obtain a `T`
17   * <p>
18   * A {@link PLens} could also be defined as a weaker {@link PIso} where set
19   * requires an additional parameter than reverseGet.
20   * <p>
21   * {@link PLens} stands for Polymorphic Lens as it set and modify methods change
22   * a type `A` to `B` and `S` to `T`. {@link Lens} is a {@link PLens} restricted
23   * to monomorphic updates.
24   * <p>
25   * A {@link PLens} is also a valid {@link Getter}, {@link Fold},
26   * {@link POptional}, {@link PTraversal} and {@link PSetter}
27   * <p>
28   * Typically a {@link PLens} or {@link Lens} can be defined between a Product
29   * (e.g. case class, tuple, HList) and one of it is component.
30   *
31   * @param <S> the source of a {@link PLens}
32   * @param <T> the modified source of a {@link PLens}
33   * @param <A> the target of a {@link PLens}
34   * @param <B> the modified target of a {@link PLens}
35   */
36  public abstract class PLens<S, T, A, B> {
37  
38    PLens() {
39      super();
40    }
41  
42    /**
43     * get the target of a {@link PLens}
44     */
45    public abstract A get(S s);
46  
47    /**
48     * set polymorphically the target of a {@link PLens} using a function
49     */
50    public abstract Function<S, T> set(B b);
51  
52    /**
53     * modify polymorphically the target of a {@link PLens} with an Applicative
54     * function
55     */
56    public abstract <C> Function<S, Function<C, T>> modifyFunctionF(Function<A, Function<C, B>> f);
57  
58    /**
59     * modify polymorphically the target of a {@link PLens} with an Applicative
60     * function
61     */
62    public abstract <L> Function<S, Either<L, T>> modifyEitherF(Function<A, Either<L, B>> f);
63  
64    /**
65     * modify polymorphically the target of a {@link PLens} with an Applicative
66     * function
67     */
68    public abstract Function<S, Option<T>> modifyOptionF(Function<A, Option<B>> f);
69  
70    /**
71     * modify polymorphically the target of a {@link PLens} with an Applicative
72     * function
73     */
74    public abstract Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f);
75  
76    /**
77     * modify polymorphically the target of a {@link PLens} with an Applicative
78     * function
79     */
80    public abstract Function<S, Supplier<T>> modifySupplierF(Function<A, Supplier<B>> f);
81  
82    /**
83     * modify polymorphically the target of a {@link PLens} with an Applicative
84     * function
85     */
86    public abstract Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f);
87  
88    /**
89     * modify polymorphically the target of a {@link PLens} using a function
90     */
91    public abstract Function<S, T> modify(final Function<A, B> f);
92  
93    /**
94     * join two {@link PLens} with the same target
95     */
96    public final <S1, T1> PLens<Either<S, S1>, Either<T, T1>, A, B> sum(final PLens<S1, T1, A, B> other) {
97      return pLens(e -> e.fold(this::get, other::get), b -> e -> e.bimap(PLens.this.set(b), other.set(b)));
98    }
99  
100   /***********************************************************/
101   /** Compose methods between a {@link PLens} and another Optics */
102   /***********************************************************/
103 
104   /**
105    * compose a {@link PLens} with a {@link Fold}
106    */
107   public final <C> Fold<S, C> composeFold(final Fold<A, C> other) {
108     return asFold().composeFold(other);
109   }
110 
111   /**
112    * compose a {@link PLens} with a {@link Getter}
113    */
114   public final <C> Getter<S, C> composeGetter(final Getter<A, C> other) {
115     return asGetter().composeGetter(other);
116   }
117 
118   /**
119    * compose a {@link PLens} with a {@link PSetter}
120    */
121   public final <C, D> PSetter<S, T, C, D> composeSetter(final PSetter<A, B, C, D> other) {
122     return asSetter().composeSetter(other);
123   }
124 
125   /**
126    * compose a {@link PLens} with a {@link PTraversal}
127    */
128   public final <C, D> PTraversal<S, T, C, D> composeTraversal(final PTraversal<A, B, C, D> other) {
129     return asTraversal().composeTraversal(other);
130   }
131 
132   /**
133    * compose a {@link PLens} with an {@link POptional}
134    */
135   public final <C, D> POptional<S, T, C, D> composeOptional(final POptional<A, B, C, D> other) {
136     return asOptional().composeOptional(other);
137   }
138 
139   /**
140    * compose a {@link PLens} with a {@link PPrism}
141    */
142   public final <C, D> POptional<S, T, C, D> composePrism(final PPrism<A, B, C, D> other) {
143     return asOptional().composeOptional(other.asOptional());
144   }
145 
146   /**
147    * compose a {@link PLens} with a {@link PLens}
148    */
149   public final <C, D> PLens<S, T, C, D> composeLens(final PLens<A, B, C, D> other) {
150     final PLens<S, T, A, B> self = this;
151     return new PLens<S, T, C, D>() {
152       @Override public C get(final S s) {
153         return other.get(self.get(s));
154       }
155 
156       @Override public Function<S, T> set(final D d) {
157         return self.modify(other.set(d));
158       }
159 
160       @Override public <G> Function<S, Function<G, T>> modifyFunctionF(final Function<C, Function<G, D>> f) {
161         return self.modifyFunctionF(other.modifyFunctionF(f));
162       }
163 
164       @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<C, Either<L, D>> f) {
165         return self.modifyEitherF(other.modifyEitherF(f));
166       }
167 
168       @Override public Function<S, Option<T>> modifyOptionF(final Function<C, Option<D>> f) {
169         return self.modifyOptionF(other.modifyOptionF(f));
170       }
171 
172       @Override public Function<S, Iterable<T>> modifyIterableF(final Function<C, Iterable<D>> f) {
173         return self.modifyIterableF(other.modifyIterableF(f));
174       }
175 
176       @Override public Function<S, Supplier<T>> modifySupplierF(final Function<C, Supplier<D>> f) {
177         return self.modifySupplierF(other.modifySupplierF(f));
178       }
179 
180       @Override public Function<S, Pair<T, T>> modifyPairF(final Function<C, Pair<D, D>> f) {
181         return self.modifyPairF(other.modifyPairF(f));
182       }
183 
184       @Override public Function<S, T> modify(final Function<C, D> f) {
185         return self.modify(other.modify(f));
186       }
187     };
188   }
189 
190   /**
191    * compose a {@link PLens} with an {@link PIso}
192    */
193   public final <C, D> PLens<S, T, C, D> composeIso(final PIso<A, B, C, D> other) {
194     return composeLens(other.asLens());
195   }
196 
197   /************************************************************************************************/
198   /** Transformation methods to view a {@link PLens} as another Optics */
199   /************************************************************************************************/
200 
201   /**
202    * view a {@link PLens} as a {@link Fold}
203    */
204   public final Fold<S, A> asFold() {
205     return new Fold<S, A>() {
206       @Override public <M> Function<S, M> foldMap(final Monoid<M> monoid, final Function<A, M> f) {
207         return s -> f.apply(get(s));
208       }
209     };
210   }
211 
212   /**
213    * view a {@link PLens} as a {@link Getter}
214    */
215   public final Getter<S, A> asGetter() {
216     return new Getter<S, A>() {
217       @Override public A get(final S s) {
218         return PLens.this.get(s);
219       }
220     };
221   }
222 
223   /**
224    * view a {@link PLens} as a {@link PSetter}
225    */
226   public PSetter<S, T, A, B> asSetter() {
227     return new PSetter<S, T, A, B>() {
228       @Override public Function<S, T> modify(final Function<A, B> f) {
229         return PLens.this.modify(f);
230       }
231 
232       @Override public Function<S, T> set(final B b) {
233         return PLens.this.set(b);
234       }
235     };
236   }
237 
238   /**
239    * view a {@link PLens} as a {@link PTraversal}
240    */
241   public PTraversal<S, T, A, B> asTraversal() {
242     final PLens<S, T, A, B> self = this;
243     return new PTraversal<S, T, A, B>() {
244 
245       @Override public <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
246         return self.modifyFunctionF(f);
247       }
248 
249       @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
250         return self.modifyEitherF(f);
251       }
252 
253       @Override public Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
254         return self.modifyOptionF(f);
255       }
256 
257       @Override public Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
258         return self.modifyIterableF(f);
259       }
260 
261       @Override public Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
262         return self.modifySupplierF(f);
263       }
264 
265       @Override public Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
266         return self.modifyPairF(f);
267       }
268 
269       @Override public <M> Function<S, M> foldMap(final Monoid<M> monoid, final Function<A, M> f) {
270         return s -> f.apply(get(s));
271       }
272 
273     };
274   }
275 
276   /**
277    * view a {@link PLens} as an {@link POptional}
278    */
279   public POptional<S, T, A, B> asOptional() {
280     final PLens<S, T, A, B> self = this;
281     return new POptional<S, T, A, B>() {
282       @Override public Either<T, A> getOrModify(final S s) {
283         return Either.right(self.get(s));
284       }
285 
286       @Override public Function<S, T> set(final B b) {
287         return self.set(b);
288       }
289 
290       @Override public Option<A> getOption(final S s) {
291         return Option.some(self.get(s));
292       }
293 
294       @Override public <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
295         return self.modifyFunctionF(f);
296       }
297 
298       @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
299         return self.modifyEitherF(f);
300       }
301 
302       @Override public Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
303         return self.modifyOptionF(f);
304       }
305 
306       @Override public Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
307         return self.modifyIterableF(f);
308       }
309 
310       @Override public Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
311         return self.modifySupplierF(f);
312       }
313 
314       @Override public Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
315         return self.modifyPairF(f);
316       }
317 
318       @Override public Function<S, T> modify(final Function<A, B> f) {
319         return self.modify(f);
320       }
321     };
322   }
323 
324   public static <S, T> PLens<S, T, S, T> pId() {
325     return PIso.<S, T> pId().asLens();
326   }
327 
328   /**
329    * create a {@link PLens} using a pair of functions: one to get the target,
330    * one to set the target.
331    */
332   public static <S, T, A, B> PLens<S, T, A, B> pLens(final Function<S, A> get, final Function<B, Function<S, T>> set) {
333     return new PLens<S, T, A, B>() {
334 
335       @Override public A get(final S s) {
336         return get.apply(s);
337       }
338 
339       @Override public Function<S, T> set(final B b) {
340         return set.apply(b);
341       }
342 
343       @Override public <C> Function<S, Function<C, T>> modifyFunctionF(final Function<A, Function<C, B>> f) {
344         return s -> f.apply(get.apply(s)).andThen(b -> set.apply(b).apply(s));
345       }
346 
347       @Override public <L> Function<S, Either<L, T>> modifyEitherF(final Function<A, Either<L, B>> f) {
348         return s -> f.apply(get.apply(s)).right().map(a -> set.apply(a).apply(s));
349       }
350 
351       @Override public Function<S, Option<T>> modifyOptionF(final Function<A, Option<B>> f) {
352         return s -> f.apply(get.apply(s)).map(a -> set.apply(a).apply(s));
353       }
354 
355       @Override public Function<S, Iterable<T>> modifyIterableF(final Function<A, Iterable<B>> f) {
356         return s -> Iterables.map(f.apply(get.apply(s)), a -> set.apply(a).apply(s));
357       }
358 
359       @Override public Function<S, Supplier<T>> modifySupplierF(final Function<A, Supplier<B>> f) {
360         return s -> Suppliers.compose(a -> set.apply(a).apply(s), f.apply(get.apply(s)));
361       }
362 
363       @Override public Function<S, Pair<T, T>> modifyPairF(final Function<A, Pair<B, B>> f) {
364         return s -> Pair.map(f.apply(get.apply(s)), a -> set.apply(a).apply(s));
365       }
366 
367       @Override public Function<S, T> modify(final Function<A, B> f) {
368         return s -> set.apply(f.apply(get.apply(s))).apply(s);
369       }
370 
371     };
372   }
373 }