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