Skip to content

Commit 369e9b6

Browse files
committed
Merge pull request #144 from orionll/master
Fixed bug in FingerTree.append(). Added PropertyTestRunner
2 parents 0613eb9 + 9305748 commit 369e9b6

File tree

9 files changed

+472
-58
lines changed

9 files changed

+472
-58
lines changed

core/src/main/java/fj/Hash.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
import fj.data.vector.V7;
1212
import fj.data.vector.V8;
1313

14+
import java.math.BigDecimal;
15+
import java.math.BigInteger;
16+
1417
/**
1518
* Produces a hash code for an object which should attempt uniqueness.
1619
*
@@ -102,6 +105,16 @@ public static <A> Hash<A> anyHash() {
102105
*/
103106
public static final Hash<Short> shortHash = anyHash();
104107

108+
/**
109+
* A hash instance for the <code>BigInteger</code> type.
110+
*/
111+
public static final Hash<BigInteger> bigintHash = anyHash();
112+
113+
/**
114+
* A hash instance for the <code>BigDecimal</code> type.
115+
*/
116+
public static final Hash<BigDecimal> bigdecimalHash = anyHash();
117+
105118
/**
106119
* A hash instance for the <code>String</code> type.
107120
*/

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

Lines changed: 153 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package fj.data;
22

3-
import fj.F;
4-
import fj.F1Functions;
3+
import fj.*;
54
import fj.function.Effect1;
65

7-
import static fj.data.Option.some;
8-
import static fj.data.Option.somes;
9-
106
import java.util.Collection;
117
import java.util.Iterator;
128

9+
import static fj.Function.identity;
10+
import static fj.data.Option.some;
11+
import static fj.data.Option.somes;
12+
1313
/**
1414
* Provides an in-memory, immutable, singly linked list with total <code>head</code> and <code>tail</code>.
1515
*
@@ -26,17 +26,19 @@ public Iterator<A> iterator() {
2626
return toCollection().iterator();
2727
}
2828

29+
private final A head;
30+
31+
private final List<A> tail;
32+
2933
/**
3034
* The first element of this linked list.
3135
*/
32-
@SuppressWarnings({"PublicField", "ClassEscapesDefinedScope"})
33-
public final A head;
36+
public A head() { return head; }
3437

3538
/**
3639
* This list without the first element.
3740
*/
38-
@SuppressWarnings({"PublicField"})
39-
public final List<A> tail;
41+
public List<A> tail() { return tail; }
4042

4143
private NonEmptyList(final A head, final List<A> tail) {
4244
this.head = head;
@@ -53,6 +55,23 @@ public NonEmptyList<A> cons(final A a) {
5355
return nel(a, tail.cons(head));
5456
}
5557

58+
/**
59+
* Appends (snoc) the given element to this non empty list to produce a new non empty list. O(n).
60+
*
61+
* @param a The element to append to this non empty list.
62+
* @return A new non empty list with the given element appended.
63+
*/
64+
public NonEmptyList<A> snoc(final A a) {
65+
return nel(head, tail.snoc(a));
66+
}
67+
68+
/**
69+
* The length of this list.
70+
*
71+
* @return The length of this list.
72+
*/
73+
public int length() { return 1 + tail.length(); }
74+
5675
/**
5776
* Appends the given list to this list.
5877
*
@@ -135,6 +154,100 @@ public <B> NonEmptyList<B> mapTails(final F<NonEmptyList<A>, B> f) {
135154
return tails().map(f);
136155
}
137156

157+
/**
158+
* Intersperses the given argument between each element of this non empty list.
159+
*
160+
* @param a The separator to intersperse in this non empty list.
161+
* @return A non empty list with the given separator interspersed.
162+
*/
163+
public NonEmptyList<A> intersperse(final A a) {
164+
final List<A> list = toList().intersperse(a);
165+
return nel(list.head(), list.tail());
166+
}
167+
168+
/**
169+
* Reverse this non empty list in constant stack space.
170+
*
171+
* @return A new non empty list with the elements in reverse order.
172+
*/
173+
public NonEmptyList<A> reverse() {
174+
final List<A> list = toList().reverse();
175+
return nel(list.head(), list.tail());
176+
}
177+
178+
/**
179+
* Sorts this non empty list using the given order over elements using a <em>merge sort</em> algorithm.
180+
*
181+
* @param o The order over the elements of this non empty list.
182+
* @return A sorted non empty list according to the given order.
183+
*/
184+
public NonEmptyList<A> sort(final Ord<A> o) {
185+
final List<A> list = toList().sort(o);
186+
return nel(list.head(), list.tail());
187+
}
188+
189+
/**
190+
* Zips this non empty list with the given non empty list to produce a list of pairs. If this list and the given list
191+
* have different lengths, then the longer list is normalised so this function never fails.
192+
*
193+
* @param bs The non empty list to zip this non empty list with.
194+
* @return A new non empty list with a length the same as the shortest of this list and the given list.
195+
*/
196+
public <B> NonEmptyList<P2<A, B>> zip(final NonEmptyList<B> bs) {
197+
final List<P2<A, B>> list = toList().zip(bs.toList());
198+
return nel(list.head(), list.tail());
199+
}
200+
201+
/**
202+
* Zips this non empty list with the index of its element as a pair.
203+
*
204+
* @return A new non empty list with the same length as this list.
205+
*/
206+
public NonEmptyList<P2<A, Integer>> zipIndex() {
207+
final List<P2<A, Integer>> list = toList().zipIndex();
208+
return nel(list.head(), list.tail());
209+
}
210+
211+
/**
212+
* Zips this non empty list with the given non empty list using the given function to produce a new list. If this list
213+
* and the given list have different lengths, then the longer list is normalised so this function
214+
* never fails.
215+
*
216+
* @param bs The non empty list to zip this non empty list with.
217+
* @param f The function to zip this non empty list and the given non empty list with.
218+
* @return A new non empty list with a length the same as the shortest of this list and the given list.
219+
*/
220+
public <B, C> NonEmptyList<C> zipWith(final List<B> bs, final F<A, F<B, C>> f) {
221+
final List<C> list = toList().zipWith(bs, f);
222+
return nel(list.head(), list.tail());
223+
}
224+
225+
/**
226+
* Zips this non empty list with the given non empty list using the given function to produce a new list. If this list
227+
* and the given list have different lengths, then the longer list is normalised so this function
228+
* never fails.
229+
*
230+
* @param bs The non empty list to zip this non empty list with.
231+
* @param f The function to zip this non empty list and the given non empty list with.
232+
* @return A new non empty list with a length the same as the shortest of this list and the given list.
233+
*/
234+
public <B, C> NonEmptyList<C> zipWith(final List<B> bs, final F2<A, B, C> f) {
235+
final List<C> list = toList().zipWith(bs, f);
236+
return nel(list.head(), list.tail());
237+
}
238+
239+
/**
240+
* Transforms a non empty list of pairs into a non empty list of first components and
241+
* a non empty list of second components.
242+
*
243+
* @param xs The non empty list of pairs to transform.
244+
* @return A non empty list of first components and a non empty list of second components.
245+
*/
246+
public static <A, B> P2<NonEmptyList<A>, NonEmptyList<B>> unzip(final NonEmptyList<P2<A, B>> xs) {
247+
final P2<List<A>, List<B>> p = List.unzip(xs.toList());
248+
return P.p(nel(p._1().head(), p._1().tail()), nel(p._2().head(), p._2().tail()));
249+
}
250+
138251
/**
139252
* Returns a <code>List</code> projection of this list.
140253
*
@@ -174,13 +287,14 @@ public static <A> NonEmptyList<A> nel(final A head, final List<A> tail) {
174287
}
175288

176289
/**
177-
* Return a non-empty list with the given value.
290+
* Constructs a non empty list from the given elements.
178291
*
179-
* @param head The value in the non-empty list.
180-
* @return A non-empty list with the given value.
292+
* @param head The first in the non-empty list.
293+
* @param tail The elements to construct a list's tail with.
294+
* @return A non-empty list with the given elements.
181295
*/
182-
public static <A> NonEmptyList<A> nel(final A head) {
183-
return nel(head, List.<A>nil());
296+
public static <A> NonEmptyList<A> nel(final A head, final A... tail) {
297+
return nel(head, List.list(tail));
184298
}
185299

186300
/**
@@ -203,4 +317,29 @@ public static <A> Option<NonEmptyList<A>> fromList(final List<A> as) {
203317
Option.<NonEmptyList<A>>none() :
204318
some(nel(as.head(), as.tail()));
205319
}
320+
321+
/**
322+
* Concatenate (join) a non empty list of non empty lists.
323+
*
324+
* @param o The non empty list of non empty lists to join.
325+
* @return A new non empty list that is the concatenation of the given lists.
326+
*/
327+
public static <A> NonEmptyList<A> join(final NonEmptyList<NonEmptyList<A>> o) { return o.bind(identity()); }
328+
329+
/**
330+
* Perform an equality test on this list which delegates to the .equals() method of the member instances.
331+
* This is implemented with Equal.nonEmptyListEqual using the anyEqual rule.
332+
*
333+
* @param obj the other object to check for equality against.
334+
* @return true if this list is equal to the provided argument
335+
*/
336+
@Override public boolean equals( final Object obj ) {
337+
return Equal.equals0(NonEmptyList.class, this, obj, () -> Equal.nonEmptyListEqual(Equal.<A>anyEqual()));
338+
}
339+
340+
@Override public int hashCode() {
341+
return Hash.nonEmptyListHash(Hash.<A>anyHash()).hash(this);
342+
}
343+
344+
@Override public String toString() { return Show.nonEmptyListShow(Show.<A>anyShow()).showS(this); }
206345
}

core/src/main/java/fj/data/fingertrees/Deep.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ private static final <V, A> FingerTree<V, A> deepR(final Measured<V, A> measured
155155
@Override public FingerTree<V, A> append(final FingerTree<V, A> t) {
156156
final Measured<V, A> m = measured();
157157
return t.match(
158-
constant(t),
158+
constant(this),
159159
single -> snoc(single.value()),
160160
deep -> new Deep<>(m, m.sum(measure(), deep.measure()), prefix,
161161
addDigits0(m, middle, suffix, deep.prefix, deep.middle), deep.suffix));

core/src/main/java/fj/test/Arbitrary.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,10 @@ public static <A> Arbitrary<List<A>> arbList(final Arbitrary<A> aa) {
733733
return arbitrary(listOf(aa.gen));
734734
}
735735

736+
public static <A> Arbitrary<NonEmptyList<A>> arbNonEmptyList(final Arbitrary<A> aa) {
737+
return arbitrary(Gen.listOf1(aa.gen).map(list -> NonEmptyList.fromList(list).some()));
738+
}
739+
736740
/**
737741
* Returns an arbitrary implementation for streams.
738742
*
@@ -761,6 +765,16 @@ public Array<A> f(final List<A> as) {
761765
}));
762766
}
763767

768+
/**
769+
* Returns an arbitrary implementation for sequences.
770+
*
771+
* @param aa An arbitrary implementation for the type over which the sequence is defined.
772+
* @return An arbitrary implementation for sequences.
773+
*/
774+
public static <A> Arbitrary<Seq<A>> arbSeq(final Arbitrary<A> aa) {
775+
return arbitrary(arbArray(aa).gen.map(array -> Seq.seq((A[]) array.array())));
776+
}
777+
764778
/**
765779
* Returns an arbitrary implementation for throwables.
766780
*

core/src/main/java/fj/test/Gen.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -554,15 +554,7 @@ public Gen<A> f(final Integer i) {
554554
* @return A generator of lists whose values come from the given generator.
555555
*/
556556
public static <A> Gen<List<A>> listOf(final Gen<A> g, final int x) {
557-
return sized(new F<Integer, Gen<List<A>>>() {
558-
public Gen<List<A>> f(final Integer size) {
559-
return choose(x, size).bind(new F<Integer, Gen<List<A>>>() {
560-
public Gen<List<A>> f(final Integer n) {
561-
return sequenceN(n, g);
562-
}
563-
});
564-
}
565-
});
557+
return sized(size -> choose(x, max(x, size)).bind(n -> sequenceN(n, g)));
566558
}
567559

568560
/**
@@ -576,7 +568,7 @@ public static <A> Gen<List<A>> listOf(final Gen<A> g) {
576568
}
577569

578570
/**
579-
* Returns a generator of lists whose values come from the given generator.
571+
* Returns a generator of non empty lists whose values come from the given generator.
580572
*
581573
* @param g The generator to produce values from for the returned generator.
582574
* @return A generator of lists whose values come from the given generator.

core/src/main/java/fj/test/Rand.java

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -124,38 +124,15 @@ public Random f(final Long x) {
124124
/**
125125
* A standard random generator that uses {@link Random}.
126126
*/
127-
public static final Rand standard = new Rand(new F<Option<Long>, F<Integer, F<Integer, Integer>>>() {
128-
public F<Integer, F<Integer, Integer>> f(final Option<Long> seed) {
129-
return new F<Integer, F<Integer, Integer>>() {
130-
public F<Integer, Integer> f(final Integer from) {
131-
return new F<Integer, Integer>() {
132-
public Integer f(final Integer to) {
133-
if(from == to){
134-
return from;
135-
}else{
136-
final int f = min(from, to);
137-
final int t = max(from, to);
138-
final int x = Math.abs(t - f);
139-
return f + seed.map(fr).orSome(new Random()).nextInt(x == Integer.MIN_VALUE ? Integer.MAX_VALUE : x);
140-
}
141-
}
142-
};
143-
}
144-
};
145-
}
146-
}, new F<Option<Long>, F<Double, F<Double, Double>>>() {
147-
public F<Double, F<Double, Double>> f(final Option<Long> seed) {
148-
return new F<Double, F<Double, Double>>() {
149-
public F<Double, Double> f(final Double from) {
150-
return new F<Double, Double>() {
151-
public Double f(final Double to) {
152-
final double f = min(from, to);
153-
final double t = max(from, to);
154-
return seed.map(fr).orSome(new Random()).nextDouble() * (t - f) + f;
155-
}
156-
};
157-
}
158-
};
159-
}
127+
public static final Rand standard = new Rand(seed -> from -> to -> {
128+
final int min = min(from, to);
129+
final int max = max(from, to);
130+
final Random random = seed.map(fr).orSome(new Random());
131+
return (int) ((random.nextLong() & Long.MAX_VALUE) % (1L + max - min)) + min;
132+
}, seed -> from -> to -> {
133+
final double min = min(from, to);
134+
final double max = max(from, to);
135+
final Random random = seed.map(fr).orSome(new Random());
136+
return random.nextDouble() * (max - min) + min;
160137
});
161138
}

0 commit comments

Comments
 (0)