Skip to content

Commit cf10026

Browse files
committed
Merge pull request functionaljava#214 from clinuxrulz/DList
DList (Difference List)
2 parents 4eb7e9e + 7753f00 commit cf10026

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ build
1414
MANIFEST.MF
1515
*/bin/**
1616
*~
17+
/.nb-gradle/

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

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package fj.data;
2+
3+
import fj.F;
4+
import fj.P;
5+
import fj.control.Trampoline;
6+
7+
/**
8+
* Difference List. It converts left associative appends into right associative ones to improve performance.
9+
*
10+
* @version %build.number%
11+
*/
12+
public class DList<A> {
13+
private final F<List<A>,Trampoline<List<A>>> appendFn;
14+
15+
private DList(F<List<A>,Trampoline<List<A>>> appendFn) {
16+
this.appendFn = appendFn;
17+
}
18+
19+
/**
20+
* Wraps a list with a DList.
21+
* @param <A>
22+
* @param a the regular List
23+
* @return the DList
24+
*/
25+
public static <A> DList<A> fromList(List<A> a) {
26+
return new DList<>((List<A> tail) -> Trampoline.pure(a.append(tail)));
27+
}
28+
29+
/**
30+
* Concatenates all the internal Lists together that are held in
31+
* the DList's lambda's state to produce a List.
32+
* This is what converts the appending operation from left associative to right associative,
33+
* giving DList it's speed.
34+
* @return the final List
35+
*/
36+
public List<A> run() {
37+
return appendFn.f(List.<A>nil()).run();
38+
}
39+
40+
/**
41+
* A empty DList.
42+
* @param <A>
43+
* @return a empty DList.
44+
*/
45+
public static <A> DList<A> nil() {
46+
return new DList<>(Trampoline.<List<A>>pure());
47+
}
48+
49+
/**
50+
* Produces a DList with one element.
51+
* @param <A>
52+
* @param a the element in the DList.
53+
* @return a DList with one element.
54+
*/
55+
public static <A> DList<A> single(A a) {
56+
return new DList<>((List<A> tail) -> Trampoline.pure(tail.cons(a)));
57+
}
58+
59+
/**
60+
* Prepends a single element on the DList to produce a new DList.
61+
* @param a the element to append.
62+
* @return the new DList.
63+
*/
64+
public DList<A> cons(A a) {
65+
return DList.single(a).append(this);
66+
}
67+
68+
/**
69+
* Appends a single element on the end of the DList to produce a new DList.
70+
* @param a the element to append.
71+
* @return the new DList.
72+
*/
73+
public DList<A> snoc(A a) {
74+
return this.append(DList.single(a));
75+
}
76+
77+
/**
78+
* Appends two DLists together to produce a new DList.
79+
* @param other the other DList to append on the end of this one.
80+
* @return the new DList.
81+
*/
82+
public DList<A> append(DList<A> other) {
83+
return new DList<>(kleisliTrampCompose(this.appendFn, other.appendFn));
84+
}
85+
86+
private static <A,B,C> F<A,Trampoline<C>> kleisliTrampCompose(F<B,Trampoline<C>> bc, F<A,Trampoline<B>> ab) {
87+
return (A a) -> ab.f(a).bind((B b) -> Trampoline.suspend(P.lazy(() -> bc.f(b))));
88+
}
89+
}

0 commit comments

Comments
 (0)