0
|
1 package fj;
|
|
2
|
|
3 import java.lang.ref.SoftReference;
|
|
4
|
|
5 import fj.data.Array;
|
|
6 import fj.data.List;
|
|
7 import fj.data.Stream;
|
|
8 import fj.data.Validation;
|
|
9 import fj.function.Try0;
|
|
10
|
|
11 public abstract class P1<A> {
|
|
12
|
|
13 /**
|
|
14 * Access the first element of the product.
|
|
15 *
|
|
16 * @return The first element of the product.
|
|
17 */
|
|
18 public abstract A _1();
|
|
19
|
|
20 /**
|
|
21 * Returns a function that returns the first element of a product.
|
|
22 *
|
|
23 * @return A function that returns the first element of a product.
|
|
24 */
|
|
25 public static <A> F<P1<A>, A> __1() {
|
|
26 return new F<P1<A>, A>() {
|
|
27 public A f(final P1<A> p) {
|
|
28 return p._1();
|
|
29 }
|
|
30 };
|
|
31 }
|
|
32
|
|
33 /**
|
|
34 * Promote any function to a transformation between P1s.
|
|
35 *
|
|
36 * @param f A function to promote to a transformation between P1s.
|
|
37 * @return A function promoted to operate on P1s.
|
|
38 */
|
|
39 public static <A, B> F<P1<A>, P1<B>> fmap(final F<A, B> f) {
|
|
40 return new F<P1<A>, P1<B>>() {
|
|
41 public P1<B> f(final P1<A> a) {
|
|
42 return a.map(f);
|
|
43 }
|
|
44 };
|
|
45 }
|
|
46
|
|
47 /**
|
|
48 * Binds the given function to the value in a product-1 with a final join.
|
|
49 *
|
|
50 * @param f A function to apply to the value in a product-1.
|
|
51 * @return The result of applying the given function to the value of given product-1.
|
|
52 */
|
|
53 public <B> P1<B> bind(final F<A, P1<B>> f) {
|
|
54 P1<A> self = this;
|
|
55 return new P1<B>() {
|
|
56 public B _1() {
|
|
57 return f.f(self._1())._1();
|
|
58 }
|
|
59 };
|
|
60 }
|
|
61
|
|
62 /**
|
|
63 * Promotes the given function so that it returns its value in a P1.
|
|
64 *
|
|
65 * @param f A function to have its result wrapped in a P1.
|
|
66 * @return A function whose result is wrapped in a P1.
|
|
67 */
|
|
68 public static <A, B> F<A, P1<B>> curry(final F<A, B> f) {
|
|
69 return new F<A, P1<B>>() {
|
|
70 public P1<B> f(final A a) {
|
|
71 return new P1<B>() {
|
|
72 public B _1() {
|
|
73 return f.f(a);
|
|
74 }
|
|
75 };
|
|
76 }
|
|
77 };
|
|
78 }
|
|
79
|
|
80 /**
|
|
81 * Performs function application within a P1 (applicative functor pattern).
|
|
82 *
|
|
83 * @param cf The P1 function to apply.
|
|
84 * @return A new P1 after applying the given P1 function to the first argument.
|
|
85 */
|
|
86 public <B> P1<B> apply(final P1<F<A, B>> cf) {
|
|
87 P1<A> self = this;
|
|
88 return cf.bind(new F<F<A, B>, P1<B>>() {
|
|
89 public P1<B> f(final F<A, B> f) {
|
|
90 return fmap(f).f(self);
|
|
91 }
|
|
92 });
|
|
93 }
|
|
94
|
|
95 /**
|
|
96 * Binds the given function to the values in the given P1s with a final join.
|
|
97 *
|
|
98 * @param cb A given P1 to bind the given function with.
|
|
99 * @param f The function to apply to the values in the given P1s.
|
|
100 * @return A new P1 after performing the map, then final join.
|
|
101 */
|
|
102 public <B, C> P1<C> bind(final P1<B> cb, final F<A, F<B, C>> f) {
|
|
103 return cb.apply(fmap(f).f(this));
|
|
104 }
|
|
105
|
|
106 /**
|
|
107 * Joins a P1 of a P1 with a bind operation.
|
|
108 *
|
|
109 * @param a The P1 of a P1 to join.
|
|
110 * @return A new P1 that is the join of the given P1.
|
|
111 */
|
|
112 public static <A> P1<A> join(final P1<P1<A>> a) {
|
|
113 return a.bind(Function.<P1<A>>identity());
|
|
114 }
|
|
115
|
|
116 /**
|
|
117 * Promotes a function of arity-2 to a function on P1s.
|
|
118 *
|
|
119 * @param f The function to promote.
|
|
120 * @return A function of arity-2 promoted to map over P1s.
|
|
121 */
|
|
122 public static <A, B, C> F<P1<A>, F<P1<B>, P1<C>>> liftM2(final F<A, F<B, C>> f) {
|
|
123 return Function.curry(new F2<P1<A>, P1<B>, P1<C>>() {
|
|
124 public P1<C> f(final P1<A> pa, final P1<B> pb) {
|
|
125 return pa.bind(pb, f);
|
|
126 }
|
|
127 });
|
|
128 }
|
|
129
|
|
130 /**
|
|
131 * Turns a List of P1s into a single P1 of a List.
|
|
132 *
|
|
133 * @param as The list of P1s to transform.
|
|
134 * @return A single P1 for the given List.
|
|
135 */
|
|
136 public static <A> P1<List<A>> sequence(final List<P1<A>> as) {
|
|
137 return as.foldRight(liftM2(List.<A>cons()), P.p(List.<A>nil()));
|
|
138 }
|
|
139
|
|
140 /**
|
|
141 * A first-class version of the sequence method for lists of P1s.
|
|
142 *
|
|
143 * @return A function from a List of P1s to a single P1 of a List.
|
|
144 */
|
|
145 public static <A> F<List<P1<A>>, P1<List<A>>> sequenceList() {
|
|
146 return new F<List<P1<A>>, P1<List<A>>>() {
|
|
147 public P1<List<A>> f(final List<P1<A>> as) {
|
|
148 return sequence(as);
|
|
149 }
|
|
150 };
|
|
151 }
|
|
152
|
|
153 /**
|
|
154 * Turns a stream of P1s into a single P1 of a stream.
|
|
155 *
|
|
156 * @param as The stream of P1s to transform.
|
|
157 * @return A single P1 for the given stream.
|
|
158 */
|
|
159 public static <A> P1<Stream<A>> sequence(final Stream<P1<A>> as) {
|
|
160 return as.foldRight(liftM2(Stream.<A>cons()), P.p(Stream.<A>nil()));
|
|
161 }
|
|
162
|
|
163 /**
|
|
164 * Turns an array of P1s into a single P1 of an array.
|
|
165 *
|
|
166 * @param as The array of P1s to transform.
|
|
167 * @return A single P1 for the given array.
|
|
168 */
|
|
169 public static <A> P1<Array<A>> sequence(final Array<P1<A>> as) {
|
|
170 return new P1<Array<A>>() {
|
|
171 public Array<A> _1() {
|
|
172 return as.map(P1.<A>__1());
|
|
173 }
|
|
174 };
|
|
175 }
|
|
176
|
|
177 /**
|
|
178 * Map the element of the product.
|
|
179 *
|
|
180 * @param f The function to map with.
|
|
181 * @return A product with the given function applied.
|
|
182 */
|
|
183 public <X> P1<X> map(final F<A, X> f) {
|
|
184 final P1<A> self = this;
|
|
185 return new P1<X>() {
|
|
186 public X _1() {
|
|
187 return f.f(self._1());
|
|
188 }
|
|
189 };
|
|
190 }
|
|
191
|
|
192 /**
|
|
193 * Provides a memoising P1 that remembers its value.
|
|
194 *
|
|
195 * @return A P1 that calls this P1 once and remembers the value for subsequent calls.
|
|
196 */
|
|
197 public P1<A> memo() {
|
|
198 final P1<A> self = this;
|
|
199 return new P1<A>() {
|
|
200 private final Object latch = new Object();
|
|
201 @SuppressWarnings({"InstanceVariableMayNotBeInitialized"})
|
|
202 private volatile SoftReference<A> v;
|
|
203
|
|
204 public A _1() {
|
|
205 A a = v != null ? v.get() : null;
|
|
206 if (a == null)
|
|
207 synchronized (latch) {
|
|
208 if (v == null || v.get() == null)
|
|
209 a = self._1();
|
|
210 v = new SoftReference<A>(a);
|
|
211 }
|
|
212 return a;
|
|
213 }
|
|
214 };
|
|
215 }
|
|
216
|
|
217 static <A> P1<A> memo(F<Unit, A> f) {
|
|
218 return P.lazy(f).memo();
|
|
219 }
|
|
220
|
|
221 /**
|
|
222 * Returns a constant function that always uses this value.
|
|
223 *
|
|
224 * @return A constant function that always uses this value.
|
|
225 */
|
|
226 public <B> F<B, A> constant() {
|
|
227
|
|
228 return new F<B, A>() {
|
|
229 public A f(final B b) {
|
|
230 return P1.this._1();
|
|
231 }
|
|
232 };
|
|
233 }
|
|
234
|
|
235 public String toString() {
|
|
236 return Show.p1Show(Show.<A>anyShow()).showS(this);
|
|
237 }
|
|
238 }
|