Exercise 7 - InfiniteList
What is InfiniteList
Main methods explanation
1
private final Lazy<Maybe<T>> head;
private final Lazy<InfiniteList<T>> tail;
private static InfiniteList<?> SENTINEL = new Sentinel();2
public static <T> InfiniteList<T> generate(Producer<T> producer) {
return new InfiniteList<>(
Lazy.of(() -> Maybe.some(producer.produce())),
Lazy.of(() -> generate(producer)));
}3
public static <T> InfiniteList<T> iterate(T seed, Transformer<T, T> next) {
return new InfiniteList<>(
Lazy.of(Maybe.some(seed)),
Lazy.of(() -> iterate(next.transform(seed), next)));
}4
public T head() {
Maybe<T> h = this.head.get();
return h.orElseGet(() -> this.tail.get().head());
}5
public InfiniteList<T> tail() {
Maybe<T> h = this.head.get();
return h.map(x -> this.tail.get()).orElseGet(() -> this.tail.get().tail());
}6
public <R> InfiniteList<R> map(Transformer<? super T, ? extends R> mapper) {
return new InfiniteList<>(
this.head.map(x -> x.map(mapper)),
this.tail.map(x -> x.map(mapper)));
}7
public InfiniteList<T> filter(BooleanCondition<? super T> predicate) {
return new InfiniteList<>(
Lazy.of(() -> this.head.get().filter(predicate)),
Lazy.of(() -> this.tail.get().filter(predicate)));
}public InfiniteList<T> filter(BooleanCondition<? super T> predicate) {
return new InfiniteList<>(
this.head.filter(predicate),
this.tail.filter(predicate));
}8
public static <T> InfiniteList<T> sentinel() {
@SuppressWarnings("unchecked")
InfiniteList<T> sentinel = (InfiniteList<T>) SENTINEL;
return sentinel;
}9
public InfiniteList<T> limit(long n) {
if (n <= 0) {
return InfiniteList.sentinel();
}
return new InfiniteList<>(
this.head,
Lazy.of(
() ->
this.head
.get()
.map(h -> this.tail.get().limit(n - 1))
.orElseGet(() -> this.tail.get().limit(n))));
}10
Lazy<Boolean> headExists = this.head.filter(
head -> !head.equals(Maybe.none()));
Lazy<Boolean> passTest = this.head.filter(
head -> !head.filter(predicate).equals(Maybe.none()));Lazy<Boolean> shouldKeepHead = headExists.combine(passTest,
(b1, b2) -> !b1 || b2);public InfiniteList<T> takeWhile(BooleanCondition<? super T> p) {
Lazy<Boolean> headExists = this.head.filter(
head -> !head.equals(Maybe.none()));
Lazy<Boolean> passTest = this.head.filter(
head -> !head.filter(p).equals(Maybe.none()));
Lazy<Boolean> shouldKeepHead = headExists.combine(passTest,
(b1, b2) -> !b1 || b2);
// Keep the head if it doesn't exist or passes the test.
return new InfiniteList<>(
shouldKeepHead.map(bool -> bool
? this.head.get()
: Maybe.none()),
shouldKeepHead.map(bool -> bool
? this.tail.map(list -> list.takeWhile(p)).get()
: InfiniteList.sentinel())
);
}11
public boolean isSentinel() {
return false;
}12
public <R> R reduce(R identity, Combiner<? super R, ? super T, ? extends R> accumulator) {
R sum = identity;
InfiniteList<T> currList = this;
while (!currList.isSentinel()) {
sum = currList.head.get()
.map(h -> accumulator.combine(sum, h))
.orElse(sum);
currList = currList.tail.get();
}
return sum;
}public <U> U reduce(U identity, Combiner<U, ? super T, U> accumulator) {
U tailResult = this.tail.get().reduce(identity, accumulator);
return this.head
.get()
.map(headVal -> accumulator.combine(tailResult, headVal))
.orElse(tailResult);
}13
public long count() {
return this.reduce(0, (x, y) -> x + 1);
}14
public List<T> toList() {
List<T> list = new ArrayList<>();
InfiniteList<T> currList = this;
while (!currList.isSentinel()) {
if (!currList.head.get().equals(Maybe.none())) {
list.add(currList.head());
}
currList = currList.tail.get();
}
return list;
}15
public void forEach(Consumer<? super T> action) {
InfiniteList<T> currList = this;
while (!currList.isSentinel()) {
// Consume the head
currList.head.get().ifPresent(action); // Do the operation
// Shrink the sublist
currList = currList.tail.get();
}
}Last updated