comparison src/main/java/fj/data/NonEmptyList.java @ 0:fe80c1edf1be

add getLoop
author tatsuki
date Fri, 20 Mar 2015 21:04:03 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:fe80c1edf1be
1 package fj.data;
2
3 import fj.F;
4 import fj.F1Functions;
5 import fj.function.Effect1;
6
7 import static fj.data.Option.some;
8 import static fj.data.Option.somes;
9
10 import java.util.Collection;
11 import java.util.Iterator;
12
13 /**
14 * Provides an in-memory, immutable, singly linked list with total <code>head</code> and <code>tail</code>.
15 *
16 * @version %build.number%
17 */
18 public final class NonEmptyList<A> implements Iterable<A> {
19 /**
20 * Returns an iterator for this non-empty list. This method exists to permit the use in a <code>for</code>-each loop.
21 *
22 * @return A iterator for this non-empty list.
23 */
24
25 public Iterator<A> iterator() {
26 return toCollection().iterator();
27 }
28
29 /**
30 * The first element of this linked list.
31 */
32 @SuppressWarnings({"PublicField", "ClassEscapesDefinedScope"})
33 public final A head;
34
35 /**
36 * This list without the first element.
37 */
38 @SuppressWarnings({"PublicField"})
39 public final List<A> tail;
40
41 private NonEmptyList(final A head, final List<A> tail) {
42 this.head = head;
43 this.tail = tail;
44 }
45
46 /**
47 * Prepend the given value to this list.
48 *
49 * @param a The value to prepend.
50 * @return A non-empty list with an extra element.
51 */
52 public NonEmptyList<A> cons(final A a) {
53 return nel(a, tail.cons(head));
54 }
55
56 /**
57 * Appends the given list to this list.
58 *
59 * @param as The list to append.
60 * @return A new list with the given list appended.
61 */
62 public NonEmptyList<A> append(final NonEmptyList<A> as) {
63 final List.Buffer<A> b = new List.Buffer<A>();
64 b.append(tail);
65 b.snoc(as.head);
66 b.append(as.tail);
67 final List<A> bb = b.toList();
68 return nel(head, bb);
69 }
70
71 /**
72 * Maps the given function across this list.
73 *
74 * @param f The function to map across this list.
75 * @return A new list after the given function has been applied to each element.
76 */
77 public <B> NonEmptyList<B> map(final F<A, B> f) {
78 return nel(f.f(head), tail.map(f));
79 }
80
81 /**
82 * Binds the given function across each element of this list with a final join.
83 *
84 * @param f The function to apply to each element of this list.
85 * @return A new list after performing the map, then final join.
86 */
87 public <B> NonEmptyList<B> bind(final F<A, NonEmptyList<B>> f) {
88 final List.Buffer<B> b = new List.Buffer<B>();
89 final NonEmptyList<B> p = f.f(head);
90 b.snoc(p.head);
91 b.append(p.tail);
92 tail.foreachDoEffect(new Effect1<A>() {
93 public void f(final A a) {
94 final NonEmptyList<B> p = f.f(a);
95 b.snoc(p.head);
96 b.append(p.tail);
97 }
98 });
99 final List<B> bb = b.toList();
100 return nel(bb.head(), bb.tail());
101 }
102
103 /**
104 * Returns a NonEmptyList of the sublists of this list.
105 *
106 * @return a NonEmptyList of the sublists of this list.
107 */
108 public NonEmptyList<NonEmptyList<A>> sublists() {
109 return fromList(
110 somes(toList().toStream().substreams()
111 .map(F1Functions.o(new F<List<A>, Option<NonEmptyList<A>>>() {
112 public Option<NonEmptyList<A>> f(final List<A> list) {
113 return fromList(list);
114 }
115 }, Conversions.<A>Stream_List())).toList())).some();
116 }
117
118 /**
119 * Returns a NonEmptyList of the tails of this list. A list is considered a tail of itself for the purpose of this
120 * function (Comonad pattern).
121 *
122 * @return A NonEmptyList of the tails of this list.
123 */
124 public NonEmptyList<NonEmptyList<A>> tails() {
125 return fromList(somes(toList().tails().map(new F<List<A>, Option<NonEmptyList<A>>>() {
126 public Option<NonEmptyList<A>> f(final List<A> list) {
127 return fromList(list);
128 }
129 }))).some();
130 }
131
132 /**
133 * Maps the given function across the tails of this list (comonad pattern).
134 *
135 * @param f The function to map across the tails of this list.
136 * @return The results of applying the given function to the tails of this list, as a NonEmptyList.
137 */
138 public <B> NonEmptyList<B> mapTails(final F<NonEmptyList<A>, B> f) {
139 return tails().map(f);
140 }
141
142 /**
143 * Returns a <code>List</code> projection of this list.
144 *
145 * @return A <code>List</code> projection of this list.
146 */
147 public List<A> toList() {
148 return tail.cons(head);
149 }
150
151 /**
152 * Projects an immutable collection of this non-empty list.
153 *
154 * @return An immutable collection of this non-empty list.
155 */
156 public Collection<A> toCollection() {
157 return toList().toCollection();
158 }
159
160 /**
161 * Returns a function that takes a non-empty list to a list.
162 *
163 * @return A function that takes a non-empty list to a list.
164 */
165 public static <A> F<NonEmptyList<A>, List<A>> toList_() {
166 return new F<NonEmptyList<A>, List<A>>() {
167 public List<A> f(final NonEmptyList<A> as) {
168 return as.toList();
169 }
170 };
171 }
172
173 /**
174 * Return a non-empty list with the given head and tail.
175 *
176 * @param head The first element of the new list.
177 * @param tail The remaining elements of the new list.
178 * @return A non-empty list with the given head and tail.
179 */
180 public static <A> NonEmptyList<A> nel(final A head, final List<A> tail) {
181 return new NonEmptyList<A>(head, tail);
182 }
183
184 /**
185 * Return a non-empty list with the given value.
186 *
187 * @param head The value in the non-empty list.
188 * @return A non-empty list with the given value.
189 */
190 public static <A> NonEmptyList<A> nel(final A head) {
191 return nel(head, List.<A>nil());
192 }
193
194 /**
195 * Returns a function that puts an element into a non-empty list.
196 *
197 * @return A function that puts an element into a non-empty list.
198 */
199 public static <A> F<A, NonEmptyList<A>> nel() {
200 return new F<A, NonEmptyList<A>>() {
201 public NonEmptyList<A> f(final A a) {
202 return nel(a);
203 }
204 };
205 }
206
207 /**
208 * Returns a potential non-empty list from the given list. A non-value is returned if the given list is empty.
209 *
210 * @param as The list to construct a potential non-empty list with.
211 * @return A potential non-empty list from the given list.
212 */
213 public static <A> Option<NonEmptyList<A>> fromList(final List<A> as) {
214 return as.isEmpty() ?
215 Option.<NonEmptyList<A>>none() :
216 some(nel(as.head(), as.tail()));
217 }
218 }