add documentation
This commit is contained in:
parent
66ed18d575
commit
0eb6cd0b30
@ -10,38 +10,44 @@ package cs2030s.fp;
|
||||
public class Actually<T> implements Immutatorable<T> {
|
||||
private T val;
|
||||
private Exception err;
|
||||
|
||||
|
||||
private Actually(T val, Exception err) {
|
||||
this.val = val;
|
||||
this.err = err;
|
||||
}
|
||||
|
||||
|
||||
public static <T> Actually<T> err() {
|
||||
// A common error for ease of use
|
||||
return new Actually<T>((T) null, new Exception("err"));
|
||||
}
|
||||
|
||||
public static <T> Actually<T> err(Exception err) {
|
||||
return new Actually<T>((T) null, err);
|
||||
}
|
||||
|
||||
public static <T> Actually<T> ok(T val) {
|
||||
return new Actually<T>(val, null);
|
||||
}
|
||||
|
||||
|
||||
public T except(Constant<? extends T> com) {
|
||||
return this.err == null ? this.val : com.init();
|
||||
}
|
||||
|
||||
public <U extends T> T unless(U val) {
|
||||
return this.err == null ? this.val : val;
|
||||
}
|
||||
|
||||
public void finish(Action<? super T> act) {
|
||||
if (this.err == null) {
|
||||
act.call(this.val);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> Actually<R> transform(Immutator<? extends R, ? super T> f) {
|
||||
return this.err == null ? Actually.<R>ok(f.invoke(this.val)) : Actually.<R>err(this.err);
|
||||
}
|
||||
|
||||
public <R> Actually<? extends R> next(Immutator<? extends Actually<? extends R>, ? super T> f) {
|
||||
if (this.err != null) {
|
||||
return Actually.err(this.err);
|
||||
@ -49,6 +55,7 @@ public class Actually<T> implements Immutatorable<T> {
|
||||
return f.invoke(this.val);
|
||||
}
|
||||
}
|
||||
|
||||
public Actually<T> check(Immutator<Boolean, ? super T> pred) {
|
||||
if (this.err != null) {
|
||||
return Actually.err(this.err);
|
||||
@ -59,7 +66,7 @@ public class Actually<T> implements Immutatorable<T> {
|
||||
}
|
||||
return Actually.err();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this.err != null) {
|
||||
@ -67,7 +74,7 @@ public class Actually<T> implements Immutatorable<T> {
|
||||
}
|
||||
return "<" + this.val + ">";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
|
@ -1,7 +1,8 @@
|
||||
package cs2030s.fp;
|
||||
|
||||
/**
|
||||
* Represent a container that can transforms its content to produce another container containing the immutated element, possible of different types.
|
||||
* Represent a container that can transforms its content to produce another
|
||||
* container containing the immutated element, possible of different types.
|
||||
* CS2030S Lab 5
|
||||
* AY22/23 Semester 1
|
||||
*
|
||||
@ -11,7 +12,8 @@ public interface Immutatorable<T> {
|
||||
/**
|
||||
* The method to produce another container with immutated element.
|
||||
*
|
||||
* @param f The immutator.
|
||||
* @param <R> The return value.
|
||||
* @param f The immutator.
|
||||
* @return A new container containing the immutated element.
|
||||
*/
|
||||
<R> Immutatorable<R> transform(Immutator<? extends R, ? super T> f);
|
||||
|
@ -4,57 +4,122 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* A list of infinite items.
|
||||
*
|
||||
* @author Yadunand Prem
|
||||
* @version CS2030S AY 22/23 Sem 1
|
||||
*/
|
||||
|
||||
public class InfiniteList<T> {
|
||||
private Memo<Actually<T>> head;
|
||||
private Memo<InfiniteList<T>> tail;
|
||||
|
||||
public static final End END = new End();
|
||||
|
||||
/**
|
||||
* end() returns the END element.
|
||||
*
|
||||
* @param <T> The type of each element in the list. Does not matter as it's the
|
||||
* end element
|
||||
* @return the End Element
|
||||
*/
|
||||
public static <T> InfiniteList<T> end() {
|
||||
@SuppressWarnings("unchecked")
|
||||
InfiniteList<T> result = (InfiniteList<T>) END;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A private constructor for InfiniteList. Use generate / iterate to generate
|
||||
*
|
||||
* @param head The head element of the list, of type T
|
||||
* @param tail The tail of the list, which is an infinite list
|
||||
*/
|
||||
private InfiniteList(Memo<Actually<T>> head, Memo<InfiniteList<T>> tail) {
|
||||
this.head = head;
|
||||
this.tail = tail;
|
||||
}
|
||||
|
||||
// You may add other private constructor but it's not necessary.
|
||||
|
||||
/**
|
||||
* Generates a list by calling prod.init()
|
||||
*
|
||||
* @param <T> The type of each element in the list
|
||||
* @param prod The producer to generate a list of items for the infinite list
|
||||
* @return The infiniteList with a generator for the tail
|
||||
*/
|
||||
public static <T> InfiniteList<T> generate(Constant<T> prod) {
|
||||
Memo<Actually<T>> head = Memo.from(() -> Actually.ok(prod.init()));
|
||||
Memo<InfiniteList<T>> tail = Memo.from(() -> generate(prod));
|
||||
return new InfiniteList<>(head, tail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a list by calling the iterator with the seed value.
|
||||
*
|
||||
* @param <T> The type of each element in the list
|
||||
* @param seed The initial value to be passed to the iterator
|
||||
* @param func The function to generate the next value in the InfiniteList
|
||||
* @return The infiniteList
|
||||
*/
|
||||
public static <T> InfiniteList<T> iterate(T seed, Immutator<T, T> func) {
|
||||
Memo<Actually<T>> head = Memo.from(Actually.ok(seed));
|
||||
Memo<InfiniteList<T>> tail = Memo.from(() -> iterate(func.invoke(seed), func));
|
||||
return new InfiniteList<>(head, tail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first valid value of the list.
|
||||
*
|
||||
* @return Returns of type T
|
||||
*/
|
||||
public T head() {
|
||||
return this.head.get().except(() -> this.tail.get().head());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the closest tail element of the list with a valid head.
|
||||
*
|
||||
* @return The InfiniteList tail
|
||||
*/
|
||||
|
||||
public InfiniteList<T> tail() {
|
||||
return this.head.get().transform(h -> this.tail.get()).except(() -> this.tail.get().tail());
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the values from type T to type R lazily.
|
||||
*
|
||||
* @param <R> The type of each element in the returned list
|
||||
* @param f The function used to map from type T to R
|
||||
* @return The InfiniteList with elements of type R
|
||||
*/
|
||||
public <R> InfiniteList<R> map(Immutator<? extends R, ? super T> f) {
|
||||
Memo<Actually<R>> head = Memo.from(() -> this.head.get().transform(f));
|
||||
Memo<InfiniteList<R>> tail = Memo.from(() -> this.tail.get().map(f));
|
||||
return new InfiniteList<R>(head, tail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the value in the infinite list based on the predicate provided
|
||||
* lazily.
|
||||
*
|
||||
* @param pred The predicate to filter the values on
|
||||
* @return The InfiniteList with filtered elements
|
||||
*/
|
||||
public InfiniteList<T> filter(Immutator<Boolean, ? super T> pred) {
|
||||
Memo<Actually<T>> head = Memo.from(() -> this.head.get().check(pred));
|
||||
Memo<InfiniteList<T>> tail = Memo.from(() -> this.tail.get().filter(pred));
|
||||
return new InfiniteList<>(head, tail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Limits the length of the InfiniteList, converting it to a finite
|
||||
* InfiniteList.
|
||||
*
|
||||
* @param n The size to limit the list to
|
||||
* @return The Finite infinite list of size n
|
||||
*/
|
||||
public InfiniteList<T> limit(long n) {
|
||||
if (n <= 0) {
|
||||
return InfiniteList.end();
|
||||
@ -67,6 +132,12 @@ public class InfiniteList<T> {
|
||||
return new InfiniteList<>(this.head, tail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes values from the InfiniteList until predicate evaluates to false lazily.
|
||||
*
|
||||
* @param pred The predicate to decide whether to stop taking values
|
||||
* @return The Maybe (if predicate is always true) InfiniteList of elements
|
||||
*/
|
||||
public InfiniteList<T> takeWhile(Immutator<Boolean, ? super T> pred) {
|
||||
Memo<Actually<T>> head = Memo.from(() -> Actually.ok(this.head()).check(pred));
|
||||
Memo<InfiniteList<T>> tail = Memo.from(() -> {
|
||||
@ -79,6 +150,12 @@ public class InfiniteList<T> {
|
||||
return new InfiniteList<>(head, tail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the InfiniteList to a List type.
|
||||
* Warning: If list is not limited, this function will cause a stack overflow.
|
||||
*
|
||||
* @return The finite list of elements converted to a List
|
||||
*/
|
||||
public List<T> toList() {
|
||||
return this.reduce(new ArrayList<>(), (acc, i) -> {
|
||||
acc.add(i);
|
||||
@ -86,25 +163,49 @@ public class InfiniteList<T> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces the elements to type U by calling acc on each element of the list,
|
||||
* with the initial value of id.
|
||||
* Warning: If list is not limited, this function will cause a stack overflow.
|
||||
*
|
||||
* @param <U> The return type of the function
|
||||
* @param id The initial value to be passed to the accumulator
|
||||
* @param acc The function used to reduce the values in the list. Initial value
|
||||
* will be head of list and id
|
||||
* @return Returns U by repeatedly calling acc on each element of the list
|
||||
*/
|
||||
public <U> U reduce(U id, Combiner<U, U, ? super T> acc) {
|
||||
return this.head.get().transform((h) -> this.tail.get().reduce(acc.combine(id, this.head.get().unless(null)), acc))
|
||||
return this.head.get()
|
||||
.transform((h) -> this.tail.get()
|
||||
.reduce(acc.combine(id, this.head.get().unless(null)), acc))
|
||||
.except(() -> this.tail.get().reduce(id, acc));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of elements in the list.
|
||||
* Warning: If list is not limited, this function will cause a stack overflow.
|
||||
*
|
||||
* @return The size of the list
|
||||
*/
|
||||
public long count() {
|
||||
return this.reduce(0L, (a, b) -> a + 1L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to check if its the end of the list.
|
||||
*
|
||||
* @return returns true if its the end of the list
|
||||
*/
|
||||
public boolean isEnd() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + this.head + " " + this.tail + "]";
|
||||
}
|
||||
|
||||
public boolean isEnd() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class End extends InfiniteList<Object> {
|
||||
private End() {
|
||||
super(null, null);
|
||||
|
@ -8,44 +8,48 @@ package cs2030s.fp;
|
||||
* @version CS2030S AY 22/23 Sem 1
|
||||
*/
|
||||
public class Memo<T> implements Immutatorable<T> {
|
||||
|
||||
|
||||
private Constant<? extends T> com;
|
||||
private Actually<T> val;
|
||||
|
||||
|
||||
private Memo(Actually<T> val, Constant<T> com) {
|
||||
this.com = com;
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
|
||||
public static <T> Memo<T> from(T val) {
|
||||
return new Memo<T>(Actually.ok(val), null);
|
||||
}
|
||||
|
||||
public static <T> Memo<T> from(Constant<T> com) {
|
||||
return new Memo<T>(Actually.err(), com);
|
||||
}
|
||||
|
||||
|
||||
public T get() {
|
||||
this.eval();
|
||||
return this.val.unless(null);
|
||||
}
|
||||
|
||||
private void eval() {
|
||||
if (this.com != null) {
|
||||
this.val = Actually.<T>ok(this.com.init());
|
||||
this.com = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <R> Memo<R> transform(Immutator<? extends R, ? super T> f) {
|
||||
return Memo.<R>from(() -> f.invoke(this.get()));
|
||||
}
|
||||
|
||||
public <R> Memo<R> next(Immutator<? extends Memo<? extends R>, ? super T> f) {
|
||||
return Memo.<R>from(() -> f.invoke(this.get()).get());
|
||||
}
|
||||
|
||||
public <S, R> Memo<R> combine(Memo<S> snd, Combiner<? extends R, ? super T, ? super S> f) {
|
||||
return Memo.<R>from(() -> f.combine(this.get(), snd.get()));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this.com != null) {
|
||||
@ -53,7 +57,7 @@ public class Memo<T> implements Immutatorable<T> {
|
||||
}
|
||||
return this.get().toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
|
Loading…
Reference in New Issue
Block a user