forked from functionaljava/functionaljava
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNonEmptyList.java
More file actions
216 lines (195 loc) · 6.03 KB
/
NonEmptyList.java
File metadata and controls
216 lines (195 loc) · 6.03 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
package fj.data;
import fj.Effect;
import fj.F;
import static fj.data.Option.some;
import static fj.data.Option.somes;
import java.util.Collection;
import java.util.Iterator;
/**
* Provides an in-memory, immutable, singly linked list with total <code>head</code> and <code>tail</code>.
*
* @version %build.number%
*/
public final class NonEmptyList<A> implements Iterable<A> {
/**
* Returns an iterator for this non-empty list. This method exists to permit the use in a <code>for</code>-each loop.
*
* @return A iterator for this non-empty list.
*/
public Iterator<A> iterator() {
return toCollection().iterator();
}
/**
* The first element of this linked list.
*/
@SuppressWarnings({"PublicField", "ClassEscapesDefinedScope"})
public final A head;
/**
* This list without the first element.
*/
@SuppressWarnings({"PublicField"})
public final List<A> tail;
private NonEmptyList(final A head, final List<A> tail) {
this.head = head;
this.tail = tail;
}
/**
* Prepend the given value to this list.
*
* @param a The value to prepend.
* @return A non-empty list with an extra element.
*/
public NonEmptyList<A> cons(final A a) {
return nel(a, tail.cons(head));
}
/**
* Appends the given list to this list.
*
* @param as The list to append.
* @return A new list with the given list appended.
*/
public NonEmptyList<A> append(final NonEmptyList<A> as) {
final List.Buffer<A> b = new List.Buffer<A>();
b.append(tail);
b.snoc(as.head);
b.append(as.tail);
final List<A> bb = b.toList();
return nel(head, bb);
}
/**
* Maps the given function across this list.
*
* @param f The function to map across this list.
* @return A new list after the given function has been applied to each element.
*/
public <B> NonEmptyList<B> map(final F<A, B> f) {
return nel(f.f(head), tail.map(f));
}
/**
* Binds the given function across each element of this list with a final join.
*
* @param f The function to apply to each element of this list.
* @return A new list after performing the map, then final join.
*/
public <B> NonEmptyList<B> bind(final F<A, NonEmptyList<B>> f) {
final List.Buffer<B> b = new List.Buffer<B>();
final NonEmptyList<B> p = f.f(head);
b.snoc(p.head);
b.append(p.tail);
tail.foreach(new Effect<A>() {
public void e(final A a) {
final NonEmptyList<B> p = f.f(a);
b.snoc(p.head);
b.append(p.tail);
}
});
final List<B> bb = b.toList();
return nel(bb.head(), bb.tail());
}
/**
* Returns a NonEmptyList of the sublists of this list.
*
* @return a NonEmptyList of the sublists of this list.
*/
public NonEmptyList<NonEmptyList<A>> sublists() {
return fromList(
somes(toList().toStream().substreams()
.map(new F<List<A>, Option<NonEmptyList<A>>>() {
public Option<NonEmptyList<A>> f(final List<A> list) {
return fromList(list);
}
}.o(Conversions.<A>Stream_List())).toList())).some();
}
/**
* Returns a NonEmptyList of the tails of this list. A list is considered a tail of itself for the purpose of this
* function (Comonad pattern).
*
* @return A NonEmptyList of the tails of this list.
*/
public NonEmptyList<NonEmptyList<A>> tails() {
return fromList(somes(toList().tails().map(new F<List<A>, Option<NonEmptyList<A>>>() {
public Option<NonEmptyList<A>> f(final List<A> list) {
return fromList(list);
}
}))).some();
}
/**
* Maps the given function across the tails of this list (comonad pattern).
*
* @param f The function to map across the tails of this list.
* @return The results of applying the given function to the tails of this list, as a NonEmptyList.
*/
public <B> NonEmptyList<B> mapTails(final F<NonEmptyList<A>, B> f) {
return tails().map(f);
}
/**
* Returns a <code>List</code> projection of this list.
*
* @return A <code>List</code> projection of this list.
*/
public List<A> toList() {
return tail.cons(head);
}
/**
* Projects an immutable collection of this non-empty list.
*
* @return An immutable collection of this non-empty list.
*/
public Collection<A> toCollection() {
return toList().toCollection();
}
/**
* Returns a function that takes a non-empty list to a list.
*
* @return A function that takes a non-empty list to a list.
*/
public static <A> F<NonEmptyList<A>, List<A>> toList_() {
return new F<NonEmptyList<A>, List<A>>() {
public List<A> f(final NonEmptyList<A> as) {
return as.toList();
}
};
}
/**
* Return a non-empty list with the given head and tail.
*
* @param head The first element of the new list.
* @param tail The remaining elements of the new list.
* @return A non-empty list with the given head and tail.
*/
public static <A> NonEmptyList<A> nel(final A head, final List<A> tail) {
return new NonEmptyList<A>(head, tail);
}
/**
* Return a non-empty list with the given value.
*
* @param head The value in the non-empty list.
* @return A non-empty list with the given value.
*/
public static <A> NonEmptyList<A> nel(final A head) {
return nel(head, List.<A>nil());
}
/**
* Returns a function that puts an element into a non-empty list.
*
* @return A function that puts an element into a non-empty list.
*/
public static <A> F<A, NonEmptyList<A>> nel() {
return new F<A, NonEmptyList<A>>() {
public NonEmptyList<A> f(final A a) {
return nel(a);
}
};
}
/**
* Returns a potential non-empty list from the given list. A non-value is returned if the given list is empty.
*
* @param as The list to construct a potential non-empty list with.
* @return A potential non-empty list from the given list.
*/
public static <A> Option<NonEmptyList<A>> fromList(final List<A> as) {
return as.isEmpty() ?
Option.<NonEmptyList<A>>none() :
some(nel(as.head(), as.tail()));
}
}