package lambdasinaction.chap14;
import java.util.function.Supplier;
import java.util.function.Predicate;
public class LazyLists {
public static void main(String[] args) {
MyList<Integer> l = new MyLinkedList<>(5, new MyLinkedList<>(10,
new Empty<Integer>()));
System.out.println(l.head());
LazyList<Integer> numbers = from(2);
int two = numbers.head();
int three = numbers.tail().head();
int four = numbers.tail().tail().head();
System.out.println(two + " " + three + " " + four);
numbers = from(2);
int prime_two = primes(numbers).head();
int prime_three = primes(numbers).tail().head();
int prime_five = primes(numbers).tail().tail().head();
System.out.println(prime_two + " " + prime_three + " " + prime_five);
// this will run until a stackoverflow occur because Java does not
// support tail call elimination
// printAll(primes(from(2)));
}
interface MyList<T> {
T head();
MyList<T> tail();
default boolean isEmpty() {
return true;
}
MyList<T> filter(Predicate<T> p);
}
static class MyLinkedList<T> implements MyList<T> {
final T head;
final MyList<T> tail;
public MyLinkedList(T head, MyList<T> tail) {
this.head = head;
this.tail = tail;
}
public T head() {
return head;
}
public MyList<T> tail() {
return tail;
}
public boolean isEmpty() {
return false;
}
public MyList<T> filter(Predicate<T> p) {
return isEmpty() ? this : p.test(head()) ? new MyLinkedList<>(
head(), tail().filter(p)) : tail().filter(p);
}
}
static class Empty<T> implements MyList<T> {
public T head() {
throw new UnsupportedOperationException();
}
public MyList<T> tail() {
throw new UnsupportedOperationException();
}
public MyList<T> filter(Predicate<T> p) {
return this;
}
}
static class LazyList<T> implements MyList<T> {
final T head;
final Supplier<MyList<T>> tail;
public LazyList(T head, Supplier<MyList<T>> tail) {
this.head = head;
this.tail = tail;
}
public T head() {
return head;
}
public MyList<T> tail() {
return tail.get();
}
public boolean isEmpty() {
return false;
}
public MyList<T> filter(Predicate<T> p) {
return isEmpty() ? this : p.test(head()) ? new LazyList<>(head(),
() -> tail().filter(p)) : tail().filter(p);
}
}
public static LazyList<Integer> from(int n) {
return new LazyList<Integer>(n, () -> from(n + 1));
}
public static MyList<Integer> primes(MyList<Integer> numbers) {
return new LazyList<>(numbers.head(), () -> primes(numbers.tail()
.filter(n -> n % numbers.head() != 0)));
}
static <T> void printAll(MyList<T> numbers) {
if (numbers.isEmpty()) {
return;
}
System.out.println(numbers.head());
printAll(numbers.tail());
}
}