Implementazione di una lista immutabile
This commit is contained in:
@@ -0,0 +1,179 @@
|
|||||||
|
package org.gym.fp.fpjava.collection;
|
||||||
|
|
||||||
|
import org.gym.fp.fpjava.type.Function;
|
||||||
|
import org.gym.fp.fpjava.type.TailCall;
|
||||||
|
|
||||||
|
import static org.gym.fp.fpjava.type.TailCall.ret;
|
||||||
|
import static org.gym.fp.fpjava.type.TailCall.suspend;
|
||||||
|
|
||||||
|
public abstract class List<A> {
|
||||||
|
|
||||||
|
public abstract A head();
|
||||||
|
|
||||||
|
public abstract List<A> tail();
|
||||||
|
|
||||||
|
public abstract boolean isEmpty();
|
||||||
|
|
||||||
|
public abstract List<A> setHead(A a);
|
||||||
|
|
||||||
|
public abstract List<A> drop(int n);
|
||||||
|
|
||||||
|
public abstract List<A> dropWhile(Function<A, Boolean> predicate);
|
||||||
|
|
||||||
|
public abstract List<A> reverse();
|
||||||
|
|
||||||
|
public abstract List<A> init();
|
||||||
|
|
||||||
|
public List<A> cons(A a) {
|
||||||
|
return new Cons<>(a, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static final List NIL = new Nil();
|
||||||
|
|
||||||
|
private List() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Nil<A> extends List<A> {
|
||||||
|
|
||||||
|
private Nil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public A head() {
|
||||||
|
throw new IllegalStateException("head called en empty list");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<A> tail() {
|
||||||
|
throw new IllegalStateException("tail called en empty list");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<A> setHead(A a) {
|
||||||
|
throw new IllegalStateException("setHead called on empty list");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<A> drop(int n) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<A> dropWhile(Function<A, Boolean> predicate) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<A> reverse() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<A> init() {
|
||||||
|
throw new IllegalStateException("init called on empty list");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[NIL]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Cons<A> extends List<A> {
|
||||||
|
private final A head;
|
||||||
|
private final List<A> tail;
|
||||||
|
|
||||||
|
private Cons(A head, List<A> tail) {
|
||||||
|
this.head = head;
|
||||||
|
this.tail = tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public A head() {
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<A> tail() {
|
||||||
|
return tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<A> setHead(A h) {
|
||||||
|
return new Cons<>(h, tail());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<A> drop(int n) {
|
||||||
|
return n <= 0 ? this : drop(this, n).eval();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<A> dropWhile(Function<A, Boolean> predicate) {
|
||||||
|
return dropWhile(this, predicate).eval();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<A> reverse() {
|
||||||
|
return reverse(list(), this).eval();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<A> init() {
|
||||||
|
return reverse().tail().reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TailCall<List<A>> reverse(List<A> acc, List<A> list) {
|
||||||
|
return list.isEmpty()
|
||||||
|
? ret(acc)
|
||||||
|
: suspend(() -> reverse(new Cons<>(list.head(), acc), list.tail()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private TailCall<List<A>> dropWhile(List<A> list, Function<A, Boolean> predicate) {
|
||||||
|
return !list.isEmpty() && predicate.apply(list.head())
|
||||||
|
? suspend(() -> dropWhile(list.tail(), predicate))
|
||||||
|
: ret(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TailCall<List<A>> drop(List<A> list, int n) {
|
||||||
|
return n <= 0 || list.isEmpty()
|
||||||
|
? ret(list)
|
||||||
|
: suspend(() -> drop(list.tail(), n - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("[%sNIL]", toString(new StringBuilder(), this).eval());
|
||||||
|
}
|
||||||
|
|
||||||
|
private TailCall<StringBuilder> toString(StringBuilder acc, List<A> list) {
|
||||||
|
return list.isEmpty()
|
||||||
|
? ret(acc)
|
||||||
|
: suspend(() -> toString(acc.append(list.head()).append(", "), list.tail()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <A> List<A> list() {
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public static <A> List<A> list(A... elements) {
|
||||||
|
List<A> n = list();
|
||||||
|
for (int i = elements.length - 1; i >= 0; i--) {
|
||||||
|
n = new Cons<>(elements[i], n);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user