forked from functionaljava/functionaljava
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHList.java
More file actions
316 lines (278 loc) · 9.45 KB
/
HList.java
File metadata and controls
316 lines (278 loc) · 9.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
package fj.data.hlist;
import fj.F;
import fj.F2;
import fj.F3;
import fj.P;
import fj.P2;
import fj.Unit;
import static fj.Function.compose;
/**
* Type-safe heterogeneous lists.
*
* @param <A> The specific type of the list, as a subtype of HList
*/
public abstract class HList<A extends HList<A>> {
HList() {
}
/**
* Extends (cons) this list by prepending the given element, returning a new list.
*
* @param e an element to prepend to this list.
* @return a new heterogeneous list, consisting of the given element prepended to this list.
*/
public abstract <E> HCons<E, A> extend(E e);
public abstract <E> Apply<Unit, P2<E, A>, HCons<E, A>> extender();
private static final HNil nil = new HNil();
/**
* Returns the empty list.
*
* @return the empty list.
*/
public static HNil nil() {
return nil;
}
/**
* Returns a heterogeneous list consisting of an element and another list.
*
* @param e an element to put in a list.
* @param l the rest of the list.
* @return a heterogeneous list consisting of an element and another list.
*/
public static <E, L extends HList<L>> HCons<E, L> cons(final E e, final L l) {
return new HCons<E, L>(e, l);
}
/**
* Returns a heterogeneous list consisting of a single element.
*
* @param e an element to put in a list
* @return a heterogeneous list consisting of a single element.
*/
public static <E> HCons<E, HNil> single(final E e) {
return cons(e, nil());
}
/**
* The concatenation of two heterogeneous lists.
*
* @param <A> The type of the first list.
* @param <B> The type of the second list.
* @param <C> The type of the combined list.
*/
public static final class HAppend<A, B, C> {
private final F2<A, B, C> append;
private HAppend(final F2<A, B, C> f) {
append = f;
}
/**
* Append a given heterogeneous list to another.
*
* @param a a heterogeneous list to be appended to.
* @param b a heterogeneous list to append to another.
* @return a new heterogeneous list consisting of the second argument appended to the first.
*/
public C append(final A a, final B b) {
return append.f(a, b);
}
/**
* Returns a method for concatenating lists to the empty list.
*
* @return a method for concatenating lists to the empty list.
*/
public static <L extends HList<L>> HAppend<HNil, L, L> append() {
return new HAppend<HNil, L, L>(new F2<HNil, L, L>() {
public L f(final HNil hNil, final L l) {
return l;
}
});
}
/**
* Returns a method for appending lists to a nonempty heterogeneous list.
*
* @param h a method for appending lists to the tail of the given nonempty list.
* @return a method for appending lists to a nonempty heterogeneous list.
*/
public static <X, A extends HList<A>, B, C extends HList<C>, H extends HAppend<A, B, C>>
HAppend<HCons<X, A>, B, HCons<X, C>> append(final H h) {
return new HAppend<HCons<X, A>, B, HCons<X, C>>(new F2<HCons<X, A>, B, HCons<X, C>>() {
public HCons<X, C> f(final HCons<X, A> c, final B l) {
return cons(c.head(), h.append(c.tail(), l));
}
});
}
}
/**
* Type-level function application operators.
*
* @param <F$> The type of the function to apply.
* @param <A> The domain of the function.
* @param <R> The function's codomain.
*/
public abstract static class Apply<F$, A, R> {
public abstract R apply(F$ f, A a);
/**
* Function application operator.
*
* @return an operator that applies a given function to a given argument.
*/
public static <X, Y> Apply<F<X, Y>, X, Y> f() {
return new Apply<F<X, Y>, X, Y>() {
public Y apply(final F<X, Y> f, final X x) {
return f.f(x);
}
};
}
/**
* Identity operator
*
* @return An operator that returns its second argument no matter which function is being applied.
*/
public static <X> Apply<Unit, X, X> id() {
return new Apply<Unit, X, X>() {
public X apply(final Unit f, final X x) {
return x;
}
};
}
/**
* A function application operator for function composition.
*
* @param <X> The domain.
* @param <Y> The type through which to compose.
* @param <Z> The codomain.
* @return an operator that composes functions.
*/
public static <X, Y, Z> Apply<Unit, P2<F<X, Y>, F<Y, Z>>, F<X, Z>> comp() {
return new Apply<Unit, P2<F<X, Y>, F<Y, Z>>, F<X, Z>>() {
public F<X, Z> apply(final Unit f, final P2<F<X, Y>, F<Y, Z>> fs) {
return compose(fs._2(), fs._1());
}
};
}
/**
* An operator for the construction of heterogeneous lists.
*
* @return an operator that constructs heterogeneous lists.
*/
public static <E, L extends HList<L>> Apply<Unit, P2<E, L>, HCons<E, L>> cons() {
return new Apply<Unit, P2<E, L>, HCons<E, L>>() {
public HCons<E, L> apply(final Unit f, final P2<E, L> p) {
return HList.cons(p._1(), p._2());
}
};
}
/**
* A function application operator for concatenating heterogeneous lists.
*
* @param <A> The type of the list to which to append.
* @param <B> The type of the list to append.
* @param <C> The type of the concatenated list.
* @return an operator that concatenates heterogeneous lists.
*/
public static <A, B, C> Apply<HAppend<A, B, C>, P2<A, B>, C> append() {
return new Apply<HAppend<A, B, C>, P2<A, B>, C>() {
public C apply(final HAppend<A, B, C> f, final P2<A, B> p) {
return f.append(p._1(), p._2());
}
};
}
}
/**
* The catamorphism over heterogeneous lists.
*
* @param <G> The type of the function with which to fold.
* @param <V> The type of the value to be substituted for the empty list.
* @param <L> The type of the heterogeneous list to be folded.
* @param <R> The return type of the fold.
*/
public static final class HFoldr<G, V, L, R> {
private final F3<G, V, L, R> foldRight;
private HFoldr(final F3<G, V, L, R> foldRight) {
this.foldRight = foldRight;
}
/**
* A fold instance for the empty list.
*
* @param <G> The type of the function with which to fold.
* @param <V> The type of value that this fold returns.
* @return a fold instance for the empty list.
*/
public static <G, V> HFoldr<G, V, HNil, V> hFoldr() {
return new HFoldr<G, V, HNil, V>(new F3<G, V, HNil, V>() {
public V f(final G f, final V v, final HNil hNil) {
return v;
}
});
}
/**
* A fold instance for a non-empty heterogeneous list
*
* @param p An operator that applies a function on the head of the list and the fold of its tail.
* @param h A fold instance for the tail of the list.
* @param <E> The type of the head of the list.
* @param <G> The type of function to apply to the head of the list and the fold of its tail.
* @param <V> The type of value to substitute for the empty list.
* @param <L> The type of the tail of the list.
* @param <R> The type of the fold of the tail of the list.
* @param <RR> The return type of the fold.
* @param <H> The type of the fold instance for the tail of the list.
* @param <PP> The type of the given function application operator.
* @return A fold instance for a non-empty heterogeneous list.
*/
public static <E, G, V, L extends HList<L>, R, RR,
H extends HFoldr<G, V, L, R>,
PP extends Apply<G, P2<E, R>, RR>>
HFoldr<G, V, HCons<E, L>, RR> hFoldr(final PP p, final H h) {
return new HFoldr<G, V, HCons<E, L>, RR>(new F3<G, V, HCons<E, L>, RR>() {
public RR f(final G f, final V v, final HCons<E, L> c) {
return p.apply(f, P.p(c.head(), h.foldRight(f, v, c.tail())));
}
});
}
/**
* Folds a non-empty heterogeneous list.
*
* @param f A function with which to fold.
* @param v The value to substitute for the empty list.
* @param l The heterogeneous list to be folded.
* @return a value obtained by folding the given list with the given function.
*/
public R foldRight(final G f, final V v, final L l) {
return foldRight.f(f, v, l);
}
}
/**
* The nonempty list
*/
public static final class HCons<E, L extends HList<L>> extends HList<HCons<E, L>> {
private final E e;
private final L l;
HCons(final E e, final L l) {
this.e = e;
this.l = l;
}
public E head() {
return e;
}
public L tail() {
return l;
}
public <X> Apply<Unit, P2<X, HCons<E, L>>, HCons<X, HCons<E, L>>> extender() {
return Apply.cons();
}
public <X> HCons<X, HCons<E, L>> extend(final X e) {
return cons(e, this);
}
}
/**
* The empty list
*/
public static final class HNil extends HList<HNil> {
HNil() {
}
public <E> HCons<E, HNil> extend(final E e) {
return cons(e, this);
}
public <E> Apply<Unit, P2<E, HNil>, HCons<E, HNil>> extender() {
return Apply.cons();
}
}
}