Skip to content

Commit daab197

Browse files
committed
2 parents 70fb0fb + 375c44e commit daab197

File tree

19 files changed

+558
-99
lines changed

19 files changed

+558
-99
lines changed

core/src/main/java/fj/data/LazyString.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
package fj.data;
22

3-
import fj.Equal;
4-
import fj.F;
5-
import fj.F2;
3+
import fj.*;
4+
65
import static fj.Function.compose;
76
import static fj.Function.curry;
87
import static fj.P.p;
9-
import fj.P1;
10-
import fj.P2;
118
import static fj.data.Option.none;
129
import static fj.data.Option.some;
1310
import static fj.data.Stream.join;
@@ -108,7 +105,9 @@ public CharSequence subSequence(final int start, final int end) {
108105
* @return The String representation of this lazy string.
109106
*/
110107
public String toString() {
111-
return new StringBuilder(length() + 16).append(this).toString();
108+
final StringBuilder builder = new StringBuilder(length() + 16);
109+
s.foreachDoEffect(c -> builder.append(c.charValue()));
110+
return builder.toString();
112111
}
113112

114113
/**

core/src/main/java/fj/data/List.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,7 @@ public final <X> Either<X, A> toEither(final F0<X> x) {
159159
* @return A stream projection of this list.
160160
*/
161161
public final Stream<A> toStream() {
162-
final Stream<A> nil = Stream.nil();
163-
return foldRight(a -> as -> as.cons(a), nil);
162+
return isEmpty() ? Stream.nil() : Stream.cons(head(), P.lazy(() -> tail().toStream()));
164163
}
165164

166165
/**
@@ -1569,7 +1568,11 @@ public static <A> List<A> replicate(final int n, final A a) {
15691568
* <code>to</code> value (exclusive).
15701569
*/
15711570
public static List<Integer> range(final int from, final int to) {
1572-
return from >= to ? List.<Integer>nil() : cons(from, range(from + 1, to));
1571+
final Buffer<Integer> buf = Buffer.empty();
1572+
for (int i = from; i < to; i++) {
1573+
buf.snoc(i);
1574+
}
1575+
return buf.toList();
15731576
}
15741577

15751578
/**

core/src/main/java/fj/data/Seq.java

Lines changed: 115 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@
1010
import fj.data.fingertrees.MakeTree;
1111
import fj.data.fingertrees.Measured;
1212

13+
import java.util.AbstractList;
14+
import java.util.Iterator;
15+
import java.util.NoSuchElementException;
16+
1317
/**
1418
* Provides an immutable finite sequence, implemented as a finger tree. This structure gives O(1) access to
1519
* the head and tail, as well as O(log n) random access and concatenation of sequences.
1620
*/
17-
public final class Seq<A> {
21+
public final class Seq<A> implements Iterable<A> {
1822
private static final Measured<Integer, Object> ELEM_MEASURED = measured(intAdditionMonoid, Function.constant(1));
1923
private static final MakeTree<Integer, Object> MK_TREE = FingerTree.mkTree(ELEM_MEASURED);
2024
private static final Seq<Object> EMPTY = new Seq<Object>(MK_TREE.empty());
@@ -88,10 +92,79 @@ public Seq<A> snoc(final A a) {
8892
return new Seq<A>(ftree.snoc(a));
8993
}
9094

95+
/**
96+
* The first element of this sequence. This is an O(1) operation.
97+
*
98+
* @return The first element if this sequence is nonempty, otherwise throws an error.
99+
*/
100+
public A head() { return ftree.head(); }
101+
102+
/**
103+
* The last element of this sequence. This is an O(1) operation.
104+
*
105+
* @return The last element if this sequence is nonempty, otherwise throws an error.
106+
*/
107+
public A last() { return ftree.last(); }
108+
109+
/**
110+
* The sequence without the first element. This is an O(1) operation.
111+
*
112+
* @return The sequence without the first element if this sequence is nonempty, otherwise throws an error.
113+
*/
114+
public Seq<A> tail() {
115+
return (length() == 1) ? empty() : new Seq<>(ftree.tail());
116+
}
117+
118+
/**
119+
* The sequence without the last element. This is an O(1) operation.
120+
*
121+
* @return The sequence without the last element if this sequence is nonempty, otherwise throws an error.
122+
*/
123+
public Seq<A> init() {
124+
return (length() == 1) ? empty() : new Seq<>(ftree.init());
125+
}
126+
91127
public Stream<A> toStream() {
92128
return ftree.foldLeft((b, a) -> b.cons(a), Stream.<A>nil()).reverse();
93129
}
94130

131+
public final java.util.List<A> toJavaList() {
132+
return new AbstractList<A>() {
133+
@Override public A get(int i) { return index(i); }
134+
@Override public Iterator<A> iterator() { return Seq.this.iterator(); }
135+
@Override public int size() { return length(); }
136+
};
137+
}
138+
139+
/**
140+
* Returns an iterator for this seq. This method exists to permit the use in a <code>for</code>-each loop.
141+
*
142+
* @return A iterator for this seq.
143+
*/
144+
public final Iterator<A> iterator() {
145+
return new Iterator<A>() {
146+
private FingerTree<Integer, A> ftree = Seq.this.ftree;
147+
148+
public boolean hasNext() {
149+
return !ftree.isEmpty();
150+
}
151+
152+
public A next() {
153+
if (ftree.isEmpty())
154+
throw new NoSuchElementException();
155+
else {
156+
final A a = ftree.head();
157+
ftree = ftree.tail();
158+
return a;
159+
}
160+
}
161+
162+
public void remove() {
163+
throw new UnsupportedOperationException();
164+
}
165+
};
166+
}
167+
95168
@Override
96169
public String toString() {
97170
return Show.seqShow(Show.<A>anyShow()).showS(this);
@@ -125,18 +198,56 @@ public int length() {
125198
return ftree.measure();
126199
}
127200

201+
public P2<Seq<A>, Seq<A>> split(final int i) {
202+
final P2<FingerTree<Integer, A>, FingerTree<Integer, A>> lr = ftree.split(index -> index > i);
203+
return P.p(new Seq<>(lr._1()), new Seq<>(lr._2()));
204+
}
205+
128206
/**
129-
* Returns the element at the given index.
207+
* Returns the element at the given index. This is an O(log(n)) operation.
130208
*
131209
* @param i The index of the element to return.
132210
* @return The element at the given index, or throws an error if the index is out of bounds.
133211
*/
134212
public A index(final int i) {
135-
if (i < 0 || i >= length())
136-
throw error("Index " + i + "out of bounds.");
213+
checkBounds(i);
137214
return ftree.lookup(Function.<Integer>identity(), i)._2();
138215
}
139216

217+
/**
218+
* Replace the element at the given index with the supplied value. This is an O(log(n)) operation.
219+
*
220+
* @param i The index of the element to update.
221+
* @param a The new value.
222+
*
223+
* @return The updated sequence, or throws an error if the index is out of bounds.
224+
*/
225+
public Seq<A> update(final int i, final A a) {
226+
checkBounds(i);
227+
final P3<FingerTree<Integer, A>, A, FingerTree<Integer, A>> lxr = ftree.split1(index -> index > i);
228+
return new Seq<>(lxr._1().append(lxr._3().cons(a)));
229+
}
230+
231+
/**
232+
* Takes the given number of elements from the head of this sequence if they are available.
233+
*
234+
* @param n The maximum number of elements to take from this sequence.
235+
* @return A sequence consisting only of the first n elements of this sequence, or else the whole sequence,
236+
* if it has less than n elements.
237+
*/
238+
public Seq<A> take(final int n) { return split(n)._1(); }
239+
240+
/**
241+
* Drops the given number of elements from the head of this sequence if they are available.
242+
*
243+
* @param n The number of elements to drop from this sequence.
244+
* @return A sequence consisting of all elements of this sequence except the first n ones, or else the empty sequence,
245+
* if this sequence has less than n elements.
246+
*/
247+
public Seq<A> drop(final int n) { return split(n)._2(); }
248+
249+
private void checkBounds(final int i) { if (i < 0 || i >= length()) throw error("Index " + i + " is out of bounds."); }
250+
140251
public <B> B foldLeft(final F2<B, A, B> f, final B z) {
141252
return ftree.foldLeft(f, z);
142253
}

core/src/main/java/fj/data/Stream.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -387,13 +387,7 @@ public final <B, C> F<B, Stream<C>> mapM(final F<A, F<B, C>> f) {
387387
* @return A new stream after performing the map, then final join.
388388
*/
389389
public final <B> Stream<B> bind(final F<A, Stream<B>> f) {
390-
return map(f).foldLeft((accumulator, element) -> {
391-
Stream<B> result = accumulator;
392-
for (B single : element) {
393-
result = result.cons(single);
394-
}
395-
return result;
396-
}, Stream.<B>nil()).reverse();
390+
return foldRight(h -> (t -> f.f(h).append(t)), nil());
397391
}
398392

399393
/**
@@ -1547,9 +1541,7 @@ public static <A> Stream<A> cons(final A head, final P1<Stream<A>> tail) {
15471541
* @param o The stream of streams to join.
15481542
* @return A new stream that is the join of the given streams.
15491543
*/
1550-
public static <A> Stream<A> join(final Stream<Stream<A>> o) {
1551-
return Monoid.<A>streamMonoid().sumRight(o);
1552-
}
1544+
public static <A> Stream<A> join(final Stream<Stream<A>> o) { return o.bind(identity()); }
15531545

15541546
/**
15551547
* A first-class version of join

0 commit comments

Comments
 (0)