package cs2030s.fp; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; public class InfiniteList { private Memo> head; private Memo> tail; public static final End END = new End(); public static InfiniteList end() { @SuppressWarnings("unchecked") InfiniteList result = (InfiniteList) END; return result; } private static class End extends InfiniteList { private End() { super(null, null); } @Override public Object head() { throw new NoSuchElementException(); } @Override public InfiniteList tail() { throw new NoSuchElementException(); } @Override public boolean isEnd() { return true; } @Override public String toString() { return "-"; } @Override public InfiniteList limit(long n) { return InfiniteList.end(); } @Override public InfiniteList filter(Immutator pred) { return InfiniteList.end(); } @Override public InfiniteList map(Immutator f) { return InfiniteList.end(); } } private InfiniteList(Memo> head, Memo> tail) { this.head = head; this.tail = tail; } // You may add other private constructor but it's not necessary. public static InfiniteList generate(Constant prod) { Memo> head = Memo.from(() -> Actually.ok(prod.init())); Memo> tail = Memo.from(() -> generate(prod)); return new InfiniteList<>(head, tail); } public static InfiniteList iterate(T seed, Immutator func) { Memo> head = Memo.from(Actually.ok(seed)); Memo> tail = Memo.from(() -> iterate(func.invoke(seed), func)); return new InfiniteList<>(head, tail); } public T head() { return this.head.get().except(() -> this.tail.get().head()); } public InfiniteList tail() { return this.head.get().transform(h -> this.tail.get()).except(() -> this.tail.get().tail()); } public InfiniteList map(Immutator f) { Memo> head = Memo.from(() -> this.head.get().transform(f)); Memo> tail = Memo.from(() -> this.tail.get().map(f)); return new InfiniteList(head, tail); } public InfiniteList filter(Immutator pred) { Memo> head = Memo.from(() -> this.head.get().check(pred)); Memo> tail = Memo.from(() -> this.tail.get().filter(pred)); return new InfiniteList<>(head, tail); } public InfiniteList limit(long n) { if (n <= 0) { return InfiniteList.end(); } Memo> head = this.head; Memo> tail = Memo.from(() -> { InfiniteList tempTail = this.tail.get(); if (tempTail.head.get().unless(null) == null) { return tempTail.limit(n); } return tempTail.limit(n - 1); }); return new InfiniteList<>(head, tail); } public InfiniteList takeWhile(Immutator pred) { // TODO return new InfiniteList<>(null, null); } public List toList() { List arrayList = new ArrayList<>(); arrayList.add(this.head()); arrayList.addAll(this.tail().toList()); return arrayList; } public U reduce(U id, Combiner acc) { // TODO return null; } public long count() { // TODO return 0L; } @Override public String toString() { return "[" + this.head + " " + this.tail + "]"; } public boolean isEnd() { return false; } // Add your End class here... }