View Javadoc

1   package io.atlassian.fugue.optic;
2   
3   import io.atlassian.fugue.Either;
4   import io.atlassian.fugue.Monoid;
5   import io.atlassian.fugue.Pair;
6   
7   import java.util.function.BinaryOperator;
8   import java.util.function.Function;
9   import java.util.function.Supplier;
10  
11  /**
12   * A {@link Getter} can be seen as a glorified get method between a type S and a
13   * type A.
14   * <p>
15   * A {@link Getter} is also a valid {@link Fold}
16   *
17   * @param <S> the source of a {@link Getter}
18   * @param <A> the target of a {@link Getter}
19   */
20  public abstract class Getter<S, A> {
21  
22    Getter() {
23      super();
24    }
25  
26    /**
27     * get the target of a {@link Getter}
28     */
29    public abstract A get(S s);
30  
31    /**
32     * join two {@link Getter} with the same target
33     */
34    public final <S1> Getter<Either<S, S1>, A> sum(final Getter<S1, A> other) {
35      return getter(e -> e.fold(this::get, other::get));
36    }
37  
38    /**
39     * pair two disjoint {@link Getter}
40     */
41    public final <S1, A1> Getter<Pair<S, S1>, Pair<A, A1>> product(final Getter<S1, A1> other) {
42      return getter(p2 -> Pair.pair(this.get(p2.left()), other.get(p2.right())));
43    }
44  
45    public final <B> Getter<Pair<S, B>, Pair<A, B>> first() {
46      return getter(p -> Pair.pair(this.get(p.left()), p.right()));
47    }
48  
49    public final <B> Getter<Pair<B, S>, Pair<B, A>> second() {
50      return getter(p -> Pair.pair(p.left(), this.get(p.right())));
51    }
52  
53    /*************************************************************/
54    /** Compose methods between a {@link Getter} and another Optics */
55    /*************************************************************/
56  
57    /**
58     * compose a {@link Getter} with a {@link Fold}
59     */
60    public final <B> Fold<S, B> composeFold(final Fold<A, B> other) {
61      return asFold().composeFold(other);
62    }
63  
64    /**
65     * compose a {@link Getter} with a {@link Getter}
66     */
67    public final <B> Getter<S, B> composeGetter(final Getter<A, B> other) {
68      return getter(s -> other.get(get(s)));
69    }
70  
71    /**
72     * compose a {@link Getter} with a {@link POptional}
73     */
74    public final <B, C, D> Fold<S, C> composeOptional(final POptional<A, B, C, D> other) {
75      return asFold().composeOptional(other);
76    }
77  
78    /**
79     * compose a {@link Getter} with a {@link PPrism}
80     */
81    public final <B, C, D> Fold<S, C> composePrism(final PPrism<A, B, C, D> other) {
82      return asFold().composePrism(other);
83    }
84  
85    /**
86     * compose a {@link Getter} with a {@link PLens}
87     */
88    public final <B, C, D> Getter<S, C> composeLens(final PLens<A, B, C, D> other) {
89      return composeGetter(other.asGetter());
90    }
91  
92    /**
93     * compose a {@link Getter} with a {@link PIso}
94     */
95    public final <B, C, D> Getter<S, C> composeIso(final PIso<A, B, C, D> other) {
96      return composeGetter(other.asGetter());
97    }
98  
99    /******************************************************************/
100   /** Transformation methods to view a {@link Getter} as another Optics */
101   /******************************************************************/
102 
103   /**
104    * view a {@link Getter} with a {@link Fold}
105    */
106   public final Fold<S, A> asFold() {
107     return new Fold<S, A>() {
108       @Override public <B> Function<S, B> foldMap(final Monoid<B> monoid, final Function<A, B> f) {
109         return s -> f.apply(get(s));
110       }
111     };
112   }
113 
114   public static <A> Getter<A, A> id() {
115     return PIso.<A, A> pId().asGetter();
116   }
117 
118   public static <A> Getter<Either<A, A>, A> codiagonal() {
119     return getter(e -> e.fold(Function.identity(), Function.identity()));
120   }
121 
122   public static <S, A> Getter<S, A> getter(final Function<S, A> get) {
123     return new Getter<S, A>() {
124 
125       @Override public A get(final S s) {
126         return get.apply(s);
127       }
128     };
129   }
130 }