Mercurial > hg > Members > tatsuki > functionaljava-master > core
diff src/main/java/fj/data/List.java @ 0:fe80c1edf1be
add getLoop
author | tatsuki |
---|---|
date | Fri, 20 Mar 2015 21:04:03 +0900 |
parents | |
children | 8ed7d71e8617 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/data/List.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,2016 @@ +package fj.data; + +import static fj.Bottom.error; +import fj.F2Functions; +import fj.Equal; +import fj.F; +import fj.F2; +import fj.F3; +import fj.Function; +import fj.Hash; +import fj.Monoid; +import fj.Ord; +import fj.P; +import fj.P1; +import fj.P2; +import fj.Show; +import fj.Unit; +import static fj.Function.curry; +import static fj.Function.constant; +import static fj.Function.identity; +import static fj.Function.compose; +import static fj.P.p; +import static fj.P.p2; +import static fj.Unit.unit; +import static fj.data.Array.mkArray; +import static fj.data.List.Buffer.*; +import static fj.data.Option.none; +import static fj.data.Option.some; +import static fj.function.Booleans.not; +import static fj.Ordering.GT; +import static fj.Ord.intOrd; + +import fj.Ordering; +import fj.control.Trampoline; +import fj.function.Effect1; + +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Provides an in-memory, immutable, singly linked list. + * + * @version %build.number% + */ +public abstract class List<A> implements Iterable<A> { + private List() { + + } + + /** + * Returns an iterator for this list. This method exists to permit the use in a <code>for</code>-each loop. + * + * @return A iterator for this list. + */ + public final Iterator<A> iterator() { + return toCollection().iterator(); + } + + /** + * The first element of the linked list or fails for the empty list. + * + * @return The first element of the linked list or fails for the empty list. + */ + public abstract A head(); + + /** + * The list without the first element or fails for the empty list. + * + * @return The list without the first element or fails for the empty list. + */ + public abstract List<A> tail(); + + /** + * The length of this list. + * + * @return The length of this list. + */ + public final int length() { + return foldLeft(new F<Integer, F<A, Integer>>() { + public F<A, Integer> f(final Integer i) { + return new F<A, Integer>() { + public Integer f(final A a) { + return i + 1; + } + }; + } + }, 0); + } + + /** + * Returns <code>true</code> if this list is empty, <code>false</code> otherwise. + * + * @return <code>true</code> if this list is empty, <code>false</code> otherwise. + */ + public final boolean isEmpty() { + return this instanceof Nil; + } + + /** + * Returns <code>false</code> if this list is empty, <code>true</code> otherwise. + * + * @return <code>false</code> if this list is empty, <code>true</code> otherwise. + */ + public final boolean isNotEmpty() { + return this instanceof Cons; + } + + /** + * Performs a reduction on this list using the given arguments. + * + * @param nil The value to return if this list is empty. + * @param cons The function to apply to the head and tail of this list if it is not empty. + * @return A reduction on this list. + */ + public final <B> B list(final B nil, final F<A, F<List<A>, B>> cons) { + return isEmpty() ? nil : cons.f(head()).f(tail()); + } + + /** + * Returns the head of this list if there is one or the given argument if this list is empty. + * + * @param a The argument to return if this list is empty. + * @return The head of this list if there is one or the given argument if this list is empty. + */ + public final A orHead(final P1<A> a) { + return isEmpty() ? a._1() : head(); + } + + /** + * Returns the tail of this list if there is one or the given argument if this list is empty. + * + * @param as The argument to return if this list is empty. + * @return The tail of this list if there is one or the given argument if this list is empty. + */ + public final List<A> orTail(final P1<List<A>> as) { + return isEmpty() ? as._1() : tail(); + } + + /** + * Returns an option projection of this list; <code>None</code> if empty, or the first element in + * <code>Some</code>. + * + * @return An option projection of this list. + */ + public final Option<A> toOption() { + return isEmpty() ? Option.<A>none() : some(head()); + } + + /** + * Returns an either projection of this list; the given argument in <code>Left</code> if empty, or + * the first element in <code>Right</code>. + * + * @param x The value to return in left if this list is empty. + * @return An either projection of this list. + */ + public final <X> Either<X, A> toEither(final P1<X> x) { + return isEmpty() ? Either.<X, A>left(x._1()) : Either.<X, A>right(head()); + } + + /** + * Returns a stream projection of this list. + * + * @return A stream projection of this list. + */ + public final Stream<A> toStream() { + final Stream<A> nil = Stream.nil(); + return foldRight(new F<A, F<Stream<A>, Stream<A>>>() { + public F<Stream<A>, Stream<A>> f(final A a) { + return new F<Stream<A>, Stream<A>>() { + public Stream<A> f(final Stream<A> as) { + return as.cons(a); + } + }; + } + }, nil); + } + + /** + * Returns a array projection of this list. + * + * @return A array projection of this list. + */ + @SuppressWarnings({"unchecked"}) + public final Array<A> toArray() { + final Object[] a = new Object[length()]; + List<A> x = this; + for (int i = 0; i < length(); i++) { + a[i] = x.head(); + x = x.tail(); + } + + return mkArray(a); + } + + /** + * Returns a array projection of this list. + * + * @param c The class type of the array to return. + * @return A array projection of this list. + */ + @SuppressWarnings({"unchecked", "UnnecessaryFullyQualifiedName"}) + public final Array<A> toArray(final Class<A[]> c) { + final A[] a = (A[]) java.lang.reflect.Array.newInstance(c.getComponentType(), length()); + List<A> x = this; + for (int i = 0; i < length(); i++) { + a[i] = x.head(); + x = x.tail(); + } + + return Array.array(a); + } + + /** + * Returns an array from this list. + * + * @param c The class type of the array to return. + * @return An array from this list. + */ + public final A[] array(final Class<A[]> c) { + return toArray(c).array(c); + } + + /** + * Prepends (cons) the given element to this list to product a new list. + * + * @param a The element to prepend. + * @return A new list with the given element at the head. + */ + public final List<A> cons(final A a) { + return new Cons<A>(a, this); + } + + /** + * Prepends (cons) the given element to this list to product a new list. This method is added to prevent conflict with + * overloads. + * + * @param a The element to prepend. + * @return A new list with the given element at the head. + */ + public final List<A> conss(final A a) { + return new Cons<A>(a, this); + } + + /** + * Maps the given function across this list. + * + * @param f The function to map across this list. + * @return A new list after the given function has been applied to each element. + */ + public final <B> List<B> map(final F<A, B> f) { + final Buffer<B> bs = empty(); + + for (List<A> xs = this; xs.isNotEmpty(); xs = xs.tail()) { + bs.snoc(f.f(xs.head())); + } + + return bs.toList(); + } + + /** + * Performs a side-effect for each element of this list. + * + * @param f The side-effect to perform for the given element. + * @return The unit value. + */ + public final Unit foreach(final F<A, Unit> f) { + for (List<A> xs = this; xs.isNotEmpty(); xs = xs.tail()) { + f.f(xs.head()); + } + + return unit(); + } + + /** + * Performs a side-effect for each element of this list. + * + * @param f The side-effect to perform for the given element. + */ + public final void foreachDoEffect(final Effect1<A> f) { + for (List<A> xs = this; xs.isNotEmpty(); xs = xs.tail()) { + f.f(xs.head()); + } + } + + /** + * Filters elements from this list by returning only elements which produce <code>true</code> when + * the given function is applied to them. + * + * @param f The predicate function to filter on. + * @return A new list whose elements all match the given predicate. + */ + public final List<A> filter(final F<A, Boolean> f) { + final Buffer<A> b = empty(); + + for (List<A> xs = this; xs.isNotEmpty(); xs = xs.tail()) { + final A h = xs.head(); + if (f.f(h)) { + b.snoc(h); + } + } + + return b.toList(); + } + + /** + * Filters elements from this list by returning only elements which produce <code>false</code> when + * the given function is applied to them. + * + * @param f The predicate function to filter on. + * @return A new list whose elements do not match the given predicate. + */ + public final List<A> removeAll(final F<A, Boolean> f) { + return filter(compose(not, f)); + } + + /** + * Removes the first element that equals the given object. + * To remove all matches, use <code>removeAll(e.eq(a))</code> + * + * @param a The element to remove + * @param e An <code>Equals</code> instance for the element's type. + * @return A new list whose elements do not match the given predicate. + */ + public final List<A> delete(final A a, final Equal<A> e) { + final P2<List<A>, List<A>> p = span(compose(not, e.eq(a))); + return p._2().isEmpty() ? p._1() : p._1().append(p._2().tail()); + } + + /** + * Returns the first elements of the head of this list that match the given predicate function. + * + * @param f The predicate function to apply on this list until it finds an element that does not + * hold, or the list is exhausted. + * @return The first elements of the head of this list that match the given predicate function. + */ + public final List<A> takeWhile(final F<A, Boolean> f) { + final Buffer<A> b = empty(); + boolean taking = true; + + for (List<A> xs = this; xs.isNotEmpty() && taking; xs = xs.tail()) { + final A h = xs.head(); + if (f.f(h)) { + b.snoc(h); + } else { + taking = false; + } + } + + return b.toList(); + } + + /** + * Removes elements from the head of this list that do not match the given predicate function + * until an element is found that does match or the list is exhausted. + * + * @param f The predicate function to apply through this list. + * @return The list whose first element does not match the given predicate function. + */ + public final List<A> dropWhile(final F<A, Boolean> f) { + List<A> xs; + + //noinspection StatementWithEmptyBody + for (xs = this; xs.isNotEmpty() && f.f(xs.head()); xs = xs.tail()) ; + + return xs; + } + + /** + * Returns a tuple where the first element is the longest prefix of this list that satisfies + * the given predicate and the second element is the remainder of the list. + * + * @param p A predicate to be satisfied by a prefix of this list. + * @return A tuple where the first element is the longest prefix of this list that satisfies + * the given predicate and the second element is the remainder of the list. + */ + public final P2<List<A>, List<A>> span(final F<A, Boolean> p) { + final Buffer<A> b = empty(); + for (List<A> xs = this; xs.isNotEmpty(); xs = xs.tail()) { + if (p.f(xs.head())) + b.snoc(xs.head()); + else + return P.p(b.toList(), xs); + } + return P.p(b.toList(), List.<A>nil()); + } + + /** + * Returns a tuple where the first element is the longest prefix of this list that does not satisfy + * the given predicate and the second element is the remainder of the list. + * + * @param p A predicate for an element to not satisfy by a prefix of this list. + * @return A tuple where the first element is the longest prefix of this list that does not satisfy + * the given predicate and the second element is the remainder of the list. + */ + public final P2<List<A>, List<A>> breakk(final F<A, Boolean> p) { + return span(new F<A, Boolean>() { + public Boolean f(final A a) { + return !p.f(a); + } + }); + } + + /** + * Groups elements according to the given equality implementation by longest + * sequence of equal elements. + * + * @param e The equality implementation for the elements. + * @return A list of grouped elements. + */ + public final List<List<A>> group(final Equal<A> e) { + if (isEmpty()) + return nil(); + else { + final P2<List<A>, List<A>> z = tail().span(e.eq(head())); + return cons(z._1().cons(head()), z._2().group(e)); + } + } + + + /** + * Binds the given function across each element of this list with a final join. + * + * @param f The function to apply to each element of this list. + * @return A new list after performing the map, then final join. + */ + public final <B> List<B> bind(final F<A, List<B>> f) { + final Buffer<B> b = empty(); + + for (List<A> xs = this; xs.isNotEmpty(); xs = xs.tail()) { + b.append(f.f(xs.head())); + } + + return b.toList(); + } + + /** + * Binds the given function across each element of this list and the given list with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given list. + * @return A new list after performing the map, then final join. + */ + public final <B, C> List<C> bind(final List<B> lb, final F<A, F<B, C>> f) { + return lb.apply(map(f)); + } + + /** + * Binds the given function across each element of this list and the given list with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given list. + * @return A new list after performing the map, then final join. + */ + public final <B, C> List<C> bind(final List<B> lb, final F2<A, B, C> f) { + return bind(lb, curry(f)); + } + + /** + * Promotes the given function of arity-2 to a function on lists. + * + * @param f The function to promote to a function on lists. + * @return The given function, promoted to operate on lists. + */ + public static <A, B, C> F<List<A>, F<List<B>, List<C>>> liftM2(final F<A, F<B, C>> f) { + return curry(new F2<List<A>, List<B>, List<C>>() { + public List<C> f(final List<A> as, final List<B> bs) { + return as.bind(bs, f); + } + }); + } + + /** + * Binds the given function across each element of this list and the given lists with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param lc A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given lists. + * @return A new list after performing the map, then final join. + */ + public final <B, C, D> List<D> bind(final List<B> lb, final List<C> lc, final F<A, F<B, F<C, D>>> f) { + return lc.apply(bind(lb, f)); + } + + /** + * Binds the given function across each element of this list and the given lists with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param lc A given list to bind the given function with. + * @param ld A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given lists. + * @return A new list after performing the map, then final join. + */ + public final <B, C, D, E> List<E> bind(final List<B> lb, final List<C> lc, final List<D> ld, + final F<A, F<B, F<C, F<D, E>>>> f) { + return ld.apply(bind(lb, lc, f)); + } + + /** + * Binds the given function across each element of this list and the given lists with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param lc A given list to bind the given function with. + * @param ld A given list to bind the given function with. + * @param le A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given lists. + * @return A new list after performing the map, then final join. + */ + public final <B, C, D, E, F$> List<F$> bind(final List<B> lb, final List<C> lc, final List<D> ld, final List<E> le, + final F<A, F<B, F<C, F<D, F<E, F$>>>>> f) { + return le.apply(bind(lb, lc, ld, f)); + } + + /** + * Binds the given function across each element of this list and the given lists with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param lc A given list to bind the given function with. + * @param ld A given list to bind the given function with. + * @param le A given list to bind the given function with. + * @param lf A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given lists. + * @return A new list after performing the map, then final join. + */ + public final <B, C, D, E, F$, G> List<G> bind(final List<B> lb, final List<C> lc, final List<D> ld, final List<E> le, + final List<F$> lf, final F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>> f) { + return lf.apply(bind(lb, lc, ld, le, f)); + } + + /** + * Binds the given function across each element of this list and the given lists with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param lc A given list to bind the given function with. + * @param ld A given list to bind the given function with. + * @param le A given list to bind the given function with. + * @param lf A given list to bind the given function with. + * @param lg A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given lists. + * @return A new list after performing the map, then final join. + */ + public final <B, C, D, E, F$, G, H> List<H> bind(final List<B> lb, final List<C> lc, final List<D> ld, final List<E> le, + final List<F$> lf, final List<G> lg, + final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>> f) { + return lg.apply(bind(lb, lc, ld, le, lf, f)); + } + + /** + * Binds the given function across each element of this list and the given lists with a final + * join. + * + * @param lb A given list to bind the given function with. + * @param lc A given list to bind the given function with. + * @param ld A given list to bind the given function with. + * @param le A given list to bind the given function with. + * @param lf A given list to bind the given function with. + * @param lg A given list to bind the given function with. + * @param lh A given list to bind the given function with. + * @param f The function to apply to each element of this list and the given lists. + * @return A new list after performing the map, then final join. + */ + public final <B, C, D, E, F$, G, H, I> List<I> bind(final List<B> lb, final List<C> lc, final List<D> ld, final List<E> le, + final List<F$> lf, final List<G> lg, final List<H> lh, + final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>> f) { + return lh.apply(bind(lb, lc, ld, le, lf, lg, f)); + } + + /** + * Performs a bind across each list element, but ignores the element value each time. + * + * @param bs The list to apply in the final join. + * @return A new list after the final join. + */ + public final <B> List<B> sequence(final List<B> bs) { + final F<A, List<B>> c = constant(bs); + return bind(c); + } + + /** + * Performs function application within a list (applicative functor pattern). + * + * @param lf The list of functions to apply. + * @return A new list after applying the given list of functions through this list. + */ + public final <B> List<B> apply(final List<F<A, B>> lf) { + return lf.bind(new F<F<A, B>, List<B>>() { + public List<B> f(final F<A, B> f) { + return map(f); + } + }); + } + + /** + * Appends the given list to this list. + * + * @param as The list to append to this one. + * @return A new list that has appended the given list. + */ + public final List<A> append(final List<A> as) { + return fromList(this).append(as).toList(); + } + + /** + * Performs a right-fold reduction across this list. This function uses O(length) stack space. + * + * @param f The function to apply on each element of the list. + * @param b The beginning value to start the application from. + * @return The final result after the right-fold reduction. + */ + public final <B> B foldRight(final F<A, F<B, B>> f, final B b) { + return isEmpty() ? b : f.f(head()).f(tail().foldRight(f, b)); + } + + /** + * Performs a right-fold reduction across this list. This function uses O(length) stack space. + * + * @param f The function to apply on each element of the list. + * @param b The beginning value to start the application from. + * @return The final result after the right-fold reduction. + */ + public final <B> B foldRight(final F2<A, B, B> f, final B b) { + return foldRight(curry(f), b); + } + + /** + * Performs a right-fold reduction across this list in O(1) stack space. + * @param f The function to apply on each element of the list. + * @param b The beginning value to start the application from. + * @return A Trampoline containing the final result after the right-fold reduction. + */ + public final <B> Trampoline<B> foldRightC(final F2<A, B, B> f, final B b) { + return Trampoline.suspend(new P1<Trampoline<B>>() { + public Trampoline<B> _1() { + return isEmpty() ? Trampoline.pure(b) : tail().foldRightC(f, b).map(F2Functions.f(f, head())); + } + }); + } + + /** + * Performs a left-fold reduction across this list. This function runs in constant space. + * + * @param f The function to apply on each element of the list. + * @param b The beginning value to start the application from. + * @return The final result after the left-fold reduction. + */ + public final <B> B foldLeft(final F<B, F<A, B>> f, final B b) { + B x = b; + + for (List<A> xs = this; !xs.isEmpty(); xs = xs.tail()) { + x = f.f(x).f(xs.head()); + } + + return x; + } + + /** + * Performs a left-fold reduction across this list. This function runs in constant space. + * + * @param f The function to apply on each element of the list. + * @param b The beginning value to start the application from. + * @return The final result after the left-fold reduction. + */ + public final <B> B foldLeft(final F2<B, A, B> f, final B b) { + return foldLeft(curry(f), b); + } + + /** + * Takes the first 2 elements of the list and applies the function to them, + * then applies the function to the result and the third element and so on. + * + * @param f The function to apply on each element of the list. + * @return The final result after the left-fold reduction. + */ + public final A foldLeft1(final F2<A, A, A> f) { + return foldLeft1(curry(f)); + } + + /** + * Takes the first 2 elements of the list and applies the function to them, + * then applies the function to the result and the third element and so on. + * + * @param f The function to apply on each element of the list. + * @return The final result after the left-fold reduction. + */ + public final A foldLeft1(final F<A, F<A, A>> f) { + if (isEmpty()) + throw error("Undefined: foldLeft1 on empty list"); + return tail().foldLeft(f, head()); + } + + /** + * Reverse this list in constant stack space. + * + * @return A new list that is the reverse of this one. + */ + public final List<A> reverse() { + return foldLeft(new F<List<A>, F<A, List<A>>>() { + public F<A, List<A>> f(final List<A> as) { + return new F<A, List<A>>() { + public List<A> f(final A a) { + return cons(a, as); + } + }; + } + }, List.<A>nil()); + } + + /** + * Returns the element at the given index if it exists, fails otherwise. + * + * @param i The index at which to get the element to return. + * @return The element at the given index if it exists, fails otherwise. + */ + public final A index(final int i) { + if (i < 0 || i > length() - 1) + throw error("index " + i + " out of range on list with length " + length()); + else { + List<A> xs = this; + + for (int c = 0; c < i; c++) { + xs = xs.tail(); + } + + return xs.head(); + } + } + + /** + * Takes the given number of elements from the head of this list if they are available. + * + * @param i The maximum number of elements to take from this list. + * @return A new list with a length the same, or less than, this list. + */ + public final List<A> take(final int i) { + return i <= 0 || isEmpty() ? List.<A>nil() : cons(head(), tail().take(i - 1)); + } + + /** + * Drops the given number of elements from the head of this list if they are available. + * + * @param i The number of elements to drop from the head of this list. + * @return A list with a length the same, or less than, this list. + */ + public final List<A> drop(final int i) { + int c = 0; + + List<A> xs = this; + + for (; xs.isNotEmpty() && c < i; xs = xs.tail()) + c++; + + return xs; + } + + /** + * Splits this list into two lists at the given index. If the index goes out of bounds, then it is + * normalised so that this function never fails. + * + * @param i The index at which to split this list in two parts. + * @return A pair of lists split at the given index of this list. + */ + public final P2<List<A>, List<A>> splitAt(final int i) { + P2<List<A>, List<A>> s = p(List.<A>nil(), List.<A>nil()); + + int c = 0; + for (List<A> xs = this; xs.isNotEmpty(); xs = xs.tail()) { + final A h = xs.head(); + s = c < i ? s.map1(new F<List<A>, List<A>>() { + public List<A> f(final List<A> as) { + return as.snoc(h); + } + }) : s.map2(new F<List<A>, List<A>>() { + public List<A> f(final List<A> as) { + return as.snoc(h); + } + }); + c++; + } + + return s; + } + + /** + * Splits this list into lists of the given size. If the size of this list is not evenly divisible by + * the given number, the last partition will contain the remainder. + * + * @param n The size of the partitions into which to split this list. + * @return A list of sublists of this list, of at most the given size. + */ + public final List<List<A>> partition(final int n) { + if (n < 1) + throw error("Can't create list partitions shorter than 1 element long."); + if (isEmpty()) + throw error("Partition on empty list."); + return unfold(new F<List<A>, Option<P2<List<A>, List<A>>>>() { + public Option<P2<List<A>, List<A>>> f(final List<A> as) { + return as.isEmpty() ? Option.<P2<List<A>, List<A>>>none() : some(as.splitAt(n)); + } + }, this); + } + + /** + * Returns the list of initial segments of this list, shortest first. + * + * @return The list of initial segments of this list, shortest first. + */ + public final List<List<A>> inits() { + List<List<A>> s = single(List.<A>nil()); + if (isNotEmpty()) + s = s.append(tail().inits().map(List.<A>cons().f(head()))); + return s; + } + + /** + * Returns the list of final segments of this list, longest first. + * + * @return The list of final segments of this list, longest first. + */ + public final List<List<A>> tails() { + return isEmpty() ? single(List.<A>nil()) : cons(this, tail().tails()); + } + + /** + * Sorts this list using the given order over elements using a <em>merge sort</em> algorithm. + * + * @param o The order over the elements of this list. + * @return A sorted list according to the given order. + */ + public final List<A> sort(final Ord<A> o) { + if (isEmpty()) + return nil(); + else if (tail().isEmpty()) + return this; + else { + final class Merge<A> { + List<A> merge(List<A> xs, List<A> ys, final Ord<A> o) { + final Buffer<A> buf = empty(); + + while (true) { + if (xs.isEmpty()) { + buf.append(ys); + break; + } + + if (ys.isEmpty()) { + buf.append(xs); + break; + } + + final A x = xs.head(); + final A y = ys.head(); + + if (o.isLessThan(x, y)) { + buf.snoc(x); + xs = xs.tail(); + } else { + buf.snoc(y); + ys = ys.tail(); + } + } + + return buf.toList(); + } + } + + final P2<List<A>, List<A>> s = splitAt(length() / 2); + return new Merge<A>().merge(s._1().sort(o), s._2().sort(o), o); + } + } + + /** + * Zips this list with the given list using the given function to produce a new list. If this list + * and the given list have different lengths, then the longer list is normalised so this function + * never fails. + * + * @param bs The list to zip this list with. + * @param f The function to zip this list and the given list with. + * @return A new list with a length the same as the shortest of this list and the given list. + */ + public final <B, C> List<C> zipWith(List<B> bs, final F<A, F<B, C>> f) { + final Buffer<C> buf = empty(); + List<A> as = this; + + while (as.isNotEmpty() && bs.isNotEmpty()) { + buf.snoc(f.f(as.head()).f(bs.head())); + as = as.tail(); + bs = bs.tail(); + } + + return buf.toList(); + } + + /** + * Zips this list with the given list using the given function to produce a new list. If this list + * and the given list have different lengths, then the longer list is normalised so this function + * never fails. + * + * @param bs The list to zip this list with. + * @param f The function to zip this list and the given list with. + * @return A new list with a length the same as the shortest of this list and the given list. + */ + public final <B, C> List<C> zipWith(final List<B> bs, final F2<A, B, C> f) { + return zipWith(bs, curry(f)); + } + + /** + * Provides a first-class version of zipWith + * + * @return The first-class version of zipWith + */ + public static <A, B, C> F<List<A>, F<List<B>, F<F<A, F<B, C>>, List<C>>>> zipWith() { + return curry(new F3<List<A>, List<B>, F<A, F<B, C>>, List<C>>() { + public List<C> f(final List<A> as, final List<B> bs, final F<A, F<B, C>> f) { + return as.zipWith(bs, f); + } + }); + } + + /** + * Zips this list with the given list to produce a list of pairs. If this list and the given list + * have different lengths, then the longer list is normalised so this function never fails. + * + * @param bs The list to zip this list with. + * @return A new list with a length the same as the shortest of this list and the given list. + */ + public final <B> List<P2<A, B>> zip(final List<B> bs) { + final F<A, F<B, P2<A, B>>> __2 = p2(); + return zipWith(bs, __2); + } + + /** + * The first-class version of the zip function. + * + * @return A function that zips the given lists to produce a list of pairs. + */ + public static <A, B> F<List<A>, F<List<B>, List<P2<A, B>>>> zip() { + return curry(new F2<List<A>, List<B>, List<P2<A, B>>>() { + public List<P2<A, B>> f(final List<A> as, final List<B> bs) { + return as.zip(bs); + } + }); + } + + /** + * Zips this list with the index of its element as a pair. + * + * @return A new list with the same length as this list. + */ + public final List<P2<A, Integer>> zipIndex() { + return zipWith(range(0, length()), new F<A, F<Integer, P2<A, Integer>>>() { + public F<Integer, P2<A, Integer>> f(final A a) { + return new F<Integer, P2<A, Integer>>() { + public P2<A, Integer> f(final Integer i) { + return p(a, i); + } + }; + } + }); + } + + /** + * Appends (snoc) the given element to this list to produce a new list. + * + * @param a The element to append to this list. + * @return A new list with the given element appended. + */ + public final List<A> snoc(final A a) { + return fromList(this).snoc(a).toList(); + } + + /** + * Returns <code>true</code> if the predicate holds for all of the elements of this list, + * <code>false</code> otherwise (<code>true</code> for the empty list). + * + * @param f The predicate function to test on each element of this list. + * @return <code>true</code> if the predicate holds for all of the elements of this list, + * <code>false</code> otherwise. + */ + public final boolean forall(final F<A, Boolean> f) { + return isEmpty() || f.f(head()) && tail().forall(f); + } + + /** + * Returns <code>true</code> if the predicate holds for at least one of the elements of this list, + * <code>false</code> otherwise (<code>false</code> for the empty list). + * + * @param f The predicate function to test on the elements of this list. + * @return <code>true</code> if the predicate holds for at least one of the elements of this + * list. + */ + public final boolean exists(final F<A, Boolean> f) { + return find(f).isSome(); + } + + /** + * Finds the first occurrence of an element that matches the given predicate or no value if no + * elements match. + * + * @param f The predicate function to test on elements of this list. + * @return The first occurrence of an element that matches the given predicate or no value if no + * elements match. + */ + public final Option<A> find(final F<A, Boolean> f) { + for (List<A> as = this; as.isNotEmpty(); as = as.tail()) { + if (f.f(as.head())) + return some(as.head()); + } + + return none(); + } + + /** + * Intersperses the given argument between each element of this list. + * + * @param a The separator to intersperse in this list. + * @return A list with the given separator interspersed. + */ + public final List<A> intersperse(final A a) { + return isEmpty() || tail().isEmpty() ? + this : + cons(head(), cons(a, tail().intersperse(a))); + } + + /** + * Intersperses this list through the given list then joins the results. + * + * @param as The list to intersperse through. + * @return This list through the given list then joins the results. + */ + @SuppressWarnings({"unchecked"}) + public final List<A> intercalate(final List<List<A>> as) { + return join(as.intersperse(this)); + } + + /** + * Removes duplicates according to object equality. + * + * @return A list without duplicates according to object equality. + */ + public final List<A> nub() { + return nub(Equal.<A>anyEqual()); + } + + /** + * Removes duplicates according to the given equality. Warning: O(n^2). + * + * @param eq Equality over the elements. + * @return A list without duplicates. + */ + public final List<A> nub(final Equal<A> eq) { + return isEmpty() ? this : cons(head(), tail().filter(new F<A, Boolean>() { + public Boolean f(final A a) { + return !eq.eq(a, head()); + } + }).nub(eq)); + } + + /** + * Removes duplicates according to the given ordering. This function is O(n). + * + * @param o An ordering for the elements. + * @return A list without duplicates. + */ + @SuppressWarnings({"unchecked"}) + public final List<A> nub(final Ord<A> o) { + return sort(o).group(o.equal()).map(List.<A>head_()); + } + + /** + * First-class head function. + * + * @return A function that gets the head of a given list. + */ + public static <A> F<List<A>, A> head_() { + return new F<List<A>, A>() { + public A f(final List<A> list) { + return list.head(); + } + }; + } + + /** + * First-class tail function. + * + * @return A function that gets the tail of a given list. + */ + public static <A> F<List<A>, List<A>> tail_() { + return new F<List<A>, List<A>>() { + public List<A> f(final List<A> list) { + return list.tail(); + } + }; + } + + /** + * Returns a new list of all the items in this list that do not appear in the given list. + * + * @param eq an equality for the items of the lists. + * @param xs a list to subtract from this list. + * @return a list of all the items in this list that do not appear in the given list. + */ + public final List<A> minus(final Equal<A> eq, final List<A> xs) { + return removeAll(compose(Monoid.disjunctionMonoid.sumLeft(), xs.mapM(curry(eq.eq())))); + } + + /** + * Maps the given function of arity-2 across this list and returns a function that applies all the resulting + * functions to a given argument. + * + * @param f A function of arity-2 + * @return A function that, when given an argument, applies the given function to that argument and every element + * in this list. + */ + public final <B, C> F<B, List<C>> mapM(final F<A, F<B, C>> f) { + return sequence_(map(f)); + } + + /** + * Maps the given function across this list by binding through the Option monad. + * + * @param f The function to apply through the this list. + * @return A possible list of values after binding through the Option monad. + */ + public final <B> Option<List<B>> mapMOption(final F<A, Option<B>> f) { + return foldRight(new F2<A, Option<List<B>>, Option<List<B>>>() { + public Option<List<B>> f(final A a, final Option<List<B>> bs) { + return f.f(a).bind(new F<B, Option<List<B>>>() { + public Option<List<B>> f(final B b) { + return bs.map(new F<List<B>, List<B>>() { + public List<B> f(final List<B> bbs) { + return bbs.cons(b); + } + }); + } + }); + } + }, Option.<List<B>>some(List.<B>nil())); + } + + /** + * Maps the given function across this list by binding through the Trampoline monad. + * + * @param f The function to apply through the this list. + * @return A list of values in the Trampoline monad. + */ + public final <B> Trampoline<List<B>> mapMTrampoline(final F<A, Trampoline<B>> f) { + return foldRight(new F2<A, Trampoline<List<B>>, Trampoline<List<B>>>() { + public Trampoline<List<B>> f(final A a, final Trampoline<List<B>> bs) { + return f.f(a).bind(new F<B, Trampoline<List<B>>>() { + public Trampoline<List<B>> f(final B b) { + return bs.map(new F<List<B>, List<B>>() { + public List<B> f(final List<B> bbs) { + return bbs.cons(b); + } + }); + } + }); + } + }, Trampoline.<List<B>>pure(List.<B>nil())); + } + + /** + * Returns the index of the first element in this list which is equal (by the given equality) to the + * query element, or None if there is no such element. + * + * @param e An equality for this list's elements. + * @param a A query element. + * @return The index of the first element in this list which is equal (by the given equality) to the + * query element, or None if there is no such element. + */ + public final Option<Integer> elementIndex(final Equal<A> e, final A a) { + return lookup(e, zipIndex(), a); + } + + /** + * Returns the last element of this list. Undefined for the empty list. + * + * @return The last element of this list or throws an error if this list is empty. + */ + public final A last() { + A a = head(); + for (List<A> xs = tail(); xs.isNotEmpty(); xs = xs.tail()) + a = xs.head(); + return a; + } + + /** + * Returns all but the last element of this list. Undefiend for the empty list. + * + * @return All but the last element of this list. Undefiend for the empty list. + */ + public final List<A> init() { + List<A> ys = this; + final Buffer<A> a = empty(); + while(ys.isNotEmpty() && ys.tail().isNotEmpty()) { + a.snoc(head()); + ys = ys.tail(); + } + return a.toList(); + } + + /** + * Inserts the given element before the first element that is greater than or equal to it according + * to the given ordering. + * + * @param f An ordering function to compare elements. + * @param x The element to insert. + * @return A new list with the given element inserted before the first element that is greater than or equal to + * it according to the given ordering. + */ + public final List<A> insertBy(final F<A, F<A, Ordering>> f, final A x) { + List<A> ys = this; + Buffer<A> xs = empty(); + while (ys.isNotEmpty() && f.f(x).f(ys.head()) == GT) { + xs = xs.snoc(ys.head()); + ys = ys.tail(); + } + return xs.append(ys.cons(x)).toList(); + } + + /** + * Returns the most common element in this list. + * + * @param o An ordering for the elements of the list. + * @return The most common element in this list. + */ + public final A mode(final Ord<A> o) { + return sort(o).group(o.equal()).maximum(intOrd.comap(List.<A>length_())).head(); + } + + /** + * Groups the elements of this list by a given keyFunction into a {@link TreeMap}. + * The ordering of the keys is determined by {@link fj.Ord#hashOrd()}. + * + * @param keyFunction The function to select the keys for the map. + * @return A TreeMap containing the keys with the accumulated list of matched elements. + */ + public final <B> TreeMap<B, List<A>> groupBy(final F<A, B> keyFunction) { + return groupBy(keyFunction, Ord.hashOrd()); + } + + /** + * Groups the elements of this list by a given keyFunction into a {@link TreeMap}. + * + * @param keyFunction The function to select the keys for the map. + * @param keyOrd An order for the keys of the tree map. + * @return A TreeMap containing the keys with the accumulated list of matched elements. + */ + public final <B> TreeMap<B, List<A>> groupBy(final F<A, B> keyFunction, final Ord<B> keyOrd) { + return groupBy(keyFunction, Function.identity(), keyOrd); + } + + /** + * Groups the elements of this list by a given keyFunction into a {@link TreeMap} and transforms + * the matching elements with the given valueFunction. The ordering of the keys is determined by + * {@link fj.Ord#hashOrd()}. + * + * @param keyFunction The function to select the keys for the map. + * @param valueFunction The function to apply on each matching value. + * @return A TreeMap containing the keys with the accumulated list of matched and mapped elements. + */ + public final <B, C> TreeMap<B, List<C>> groupBy( + final F<A, B> keyFunction, + final F<A, C> valueFunction) { + return this.groupBy(keyFunction, valueFunction, Ord.hashOrd()); + } + + /** + * Groups the elements of this list by a given keyFunction into a {@link TreeMap} and transforms + * the matching elements with the given valueFunction. The ordering of the keys is determined by + * the keyOrd parameter. + * + * @param keyFunction The function to select the keys for the map. + * @param valueFunction The function to apply on each matching value. + * @param keyOrd An order for the keys of the tree map. + * @return A TreeMap containing the keys with the accumulated list of matched and mapped elements. + */ + public final <B, C> TreeMap<B, List<C>> groupBy( + final F<A, B> keyFunction, + final F<A, C> valueFunction, + final Ord<B> keyOrd) { + return this.groupBy(keyFunction, valueFunction, List.<C>nil(), List::cons, keyOrd); + } + + /** + * Groups the elements of this list by a given keyFunction into a {@link TreeMap} and transforms + * the matching elements with the given valueFunction. The ordering of the keys is determined by + * the keyOrd parameter. + * + * @param keyFunction The function to select the keys for the map. + * @param valueFunction The function to apply on each matching value. + * @param monoid A monoid, which defines the accumulator for the values and the zero value. + * @param keyOrd An order for the keys of the tree map. + * @return A TreeMap containing the keys with the accumulated list of matched and mapped elements. + */ + public final <B, C> TreeMap<B, C> groupBy( + final F<A, B> keyFunction, + final F<A, C> valueFunction, + final Monoid<C> monoid, + final Ord<B> keyOrd) { + return groupBy(keyFunction, valueFunction, monoid.zero(), + Function.uncurryF2(monoid.sum()), keyOrd); + } + + /** + * Groups the elements of this list by a given keyFunction, applies the valueFunction and + * accumulates the mapped values with the given grouping accumulator function on the grouping + * identity. + * + * @param keyFunction The function to select the keys. + * @param valueFunction The function to apply on each element. + * @param groupingIdentity The identity, or start value, for the grouping. + * @param groupingAcc The accumulator to apply on each matching value. + * @param keyOrd An order for the keys of the tree map. + * @return A TreeMap containing the keys with the accumulated result of matched and mapped + * elements. + */ + public final <B, C, D> TreeMap<B, D> groupBy( + final F<A, B> keyFunction, + final F<A, C> valueFunction, + final D groupingIdentity, + final F2<C, D, D> groupingAcc, + final Ord<B> keyOrd) { + return this.foldLeft(map -> element -> { + final B key = keyFunction.f(element); + final C value = valueFunction.f(element); + return map.set(key, map.get(key) + .map(existing -> groupingAcc.f(value, existing)) + .orSome(groupingAcc.f(value, groupingIdentity))); + }, TreeMap.<B, D>empty(keyOrd) + ); + } + + + + /** + * Returns whether or not all elements in the list are equal according to the given equality test. + * + * @param eq The equality test. + * @return Whether or not all elements in the list are equal according to the given equality test. + */ + public boolean allEqual(final Equal<A> eq) { + return isEmpty() || tail().isEmpty() || eq.eq(head(), tail().head()) && tail().allEqual(eq); + } + + /** + * First-class length. + * + * @return A function that gets the length of a given list. + */ + public static <A> F<List<A>, Integer> length_() { + return new F<List<A>, Integer>() { + public Integer f(final List<A> a) { + return a.length(); + } + }; + } + + /** + * Returns the maximum element in this list according to the given ordering. + * + * @param o An ordering for the elements of the list. + * @return The maximum element in this list according to the given ordering. + */ + public final A maximum(final Ord<A> o) { + return foldLeft1(o.max); + } + + /** + * Returns the minimum element in this list according to the given ordering. + * + * @param o An ordering for the elements of the list. + * @return The minimum element in this list according to the given ordering. + */ + public final A minimum(final Ord<A> o) { + return foldLeft1(o.min); + } + + /** + * Projects an immutable collection of this list. + * + * @return An immutable collection of this list. + */ + public final Collection<A> toCollection() { + return new AbstractCollection<A>() { + public Iterator<A> iterator() { + return new Iterator<A>() { + private List<A> xs = List.this; + + public boolean hasNext() { + return xs.isNotEmpty(); + } + + public A next() { + if (xs.isEmpty()) + throw new NoSuchElementException(); + else { + final A a = xs.head(); + xs = xs.tail(); + return a; + } + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + public int size() { + return length(); + } + }; + } + + private static final class Nil<A> extends List<A> { + public static final Nil<Object> INSTANCE = new Nil<Object>(); + + public A head() { + throw error("head on empty list"); + } + + public List<A> tail() { + throw error("tail on empty list"); + } + } + + private static final class Cons<A> extends List<A> { + private final A head; + private List<A> tail; + + Cons(final A head, final List<A> tail) { + this.head = head; + this.tail = tail; + } + + public A head() { + return head; + } + + public List<A> tail() { + return tail; + } + + private void tail(final List<A> tail) { + this.tail = tail; + } + } + + /** + * Constructs a list from the given elements. + * + * @param as The elements to construct a list with. + * @return A list with the given elements. + */ + public static <A> List<A> list(final A... as) { + return Array.array(as).toList(); + } + + /** + * Returns an empty list. + * + * @return An empty list. + */ + @SuppressWarnings("unchecked") + public static <A> List<A> nil() { + return (Nil<A>) Nil.INSTANCE; + } + + /** + * Returns a function that prepends (cons) an element to a list to produce a new list. + * + * @return A function that prepends (cons) an element to a list to produce a new list. + */ + public static <A> F<A, F<List<A>, List<A>>> cons() { + return new F<A, F<List<A>, List<A>>>() { + public F<List<A>, List<A>> f(final A a) { + return new F<List<A>, List<A>>() { + public List<A> f(final List<A> tail) { + return cons(a, tail); + } + }; + } + }; + } + + public static <A> F2<A, List<A>, List<A>> cons_() { + return (a, listA) -> cons(a, listA); + } + + /** + * Returns a function that prepends a value to the given list. + * + * @param tail The list to prepend to. + * @return A function that prepends a value to the given list. + */ + public static <A> F<A, List<A>> cons(final List<A> tail) { + return new F<A, List<A>>() { + public List<A> f(final A a) { + return tail.cons(a); + } + }; + } + + /** + * Returns a function that prepends the given value to a list. + * + * @param a The value to prepend to a list. + * @return A function that prepends the given value to a list. + */ + public static <A> F<List<A>, List<A>> cons_(final A a) { + return new F<List<A>, List<A>>() { + public List<A> f(final List<A> as) { + return as.cons(a); + } + }; + } + + /** + * Prepends the given head element to the given tail element to produce a new list. + * + * @param head The element to prepend. + * @param tail The list to prepend to. + * @return The list with the given element prepended. + */ + public static <A> List<A> cons(final A head, final List<A> tail) { + return new Cons<A>(head, tail); + } + + /** + * Returns a function that determines whether a given list is empty. + * + * @return A function that determines whether a given list is empty. + */ + public static <A> F<List<A>, Boolean> isEmpty_() { + return new F<List<A>, Boolean>() { + public Boolean f(final List<A> as) { + return as.isEmpty(); + } + }; + } + + /** + * Returns a function that determines whether a given list is not empty. + * + * @return A function that determines whether a given list is not empty. + */ + public static <A> F<List<A>, Boolean> isNotEmpty_() { + return new F<List<A>, Boolean>() { + public Boolean f(final List<A> as) { + return as.isNotEmpty(); + } + }; + } + + /** + * Joins the given list of lists using a bind operation. + * + * @param o The list of lists to join. + * @return A new list that is the join of the given lists. + */ + public static <A> List<A> join(final List<List<A>> o) { + final F<List<A>, List<A>> id = identity(); + return o.bind(id); + } + + /** + * A first-class version of join + * + * @return A function that joins a list of lists using a bind operation. + */ + public static <A> F<List<List<A>>, List<A>> join() { + return new F<List<List<A>>, List<A>>() { + public List<A> f(final List<List<A>> as) { + return join(as); + } + }; + } + + /** + * Unfolds across the given function starting at the given value to produce a list. + * + * @param f The function to unfold across. + * @param b The start value to begin the unfold. + * @return A new list that is a result of unfolding until the function does not produce a value. + */ + public static <A, B> List<A> unfold(final F<B, Option<P2<A, B>>> f, final B b) { + Buffer<A> buf = empty(); + for (Option<P2<A, B>> o = f.f(b); o.isSome(); o = f.f(o.some()._2())) { + buf = buf.snoc(o.some()._1()); + } + return buf.toList(); + } + + /** + * Transforms a list of pairs into a list of first components and a list of second components. + * + * @param xs The list of pairs to transform.sp + * @return A list of first components and a list of second components. + */ + public static <A, B> P2<List<A>, List<B>> unzip(final List<P2<A, B>> xs) { + Buffer<A> ba = empty(); + Buffer<B> bb = empty(); + for (final P2<A, B> p : xs) { + ba = ba.snoc(p._1()); + bb = bb.snoc(p._2()); + } + return P.p(ba.toList(), bb.toList()); + } + + /** + * Returns a list of the given value replicated the given number of times. + * + * @param n The number of times to replicate the given value. + * @param a The value to replicate. + * @return A list of the given value replicated the given number of times. + */ + public static <A> List<A> replicate(final int n, final A a) { + return n <= 0 ? List.<A>nil() : replicate(n - 1, a).cons(a); + } + + /** + * Returns a list of integers from the given <code>from</code> value (inclusive) to the given + * <code>to</code> value (exclusive). + * + * @param from The minimum value for the list (inclusive). + * @param to The maximum value for the list (exclusive). + * @return A list of integers from the given <code>from</code> value (inclusive) to the given + * <code>to</code> value (exclusive). + */ + public static List<Integer> range(final int from, final int to) { + return from >= to ? List.<Integer>nil() : cons(from, range(from + 1, to)); + } + + /** + * Returns a list of characters from the given string. The inverse of this function is {@link + * #asString(List)}. + * + * @param s The string to produce the list of characters from. + * @return A list of characters from the given string. + */ + public static List<Character> fromString(final String s) { + List<Character> cs = nil(); + + for (int i = s.length() - 1; i >= 0; i--) + cs = cons(s.charAt(i), cs); + + return cs; + } + + /** + * A first-class <code>fromString</code>. + * + * @return A first-class <code>fromString</code>. + */ + public static F<String, List<Character>> fromString() { + return new F<String, List<Character>>() { + public List<Character> f(final String s) { + return fromString(s); + } + }; + } + + /** + * Returns a string from the given list of characters. The invers of this function is {@link + * #fromString(String)}. + * + * @param cs The list of characters to produce the string from. + * @return A string from the given list of characters. + */ + public static String asString(final List<Character> cs) { + final StringBuilder sb = new StringBuilder(); + + cs.foreach(new F<Character, Unit>() { + public Unit f(final Character c) { + sb.append(c); + return unit(); + } + }); + return sb.toString(); + } + + /** + * A first-class <code>asString</code>. + * + * @return A first-class <code>asString</code>. + */ + public static F<List<Character>, String> asString() { + return new F<List<Character>, String>() { + public String f(final List<Character> cs) { + return asString(cs); + } + }; + } + + /** + * Returns a list of one element containing the given value. + * + * @param a The value for the head of the returned list. + * @return A list of one element containing the given value. + */ + public static <A> List<A> single(final A a) { + return cons(a, List.<A>nil()); + } + + /** + * Creates a list where the first item is calculated by applying the function on the third argument, + * the second item by applying the function on the previous result and so on. + * + * @param f The function to iterate with. + * @param p The predicate which must be true for the next item in order to continue the iteration. + * @param a The input to the first iteration. + * @return A list where the first item is calculated by applying the function on the third argument, + * the second item by applying the function on the previous result and so on. + */ + public static <A> List<A> iterateWhile(final F<A, A> f, final F<A, Boolean> p, final A a) { + return unfold( + new F<A, Option<P2<A, A>>>() { + public Option<P2<A, A>> f(final A o) { + return Option.iif(new F<P2<A, A>, Boolean>() { + public Boolean f(final P2<A, A> p2) { + return p.f(o); + } + }, P.p(o, f.f(o))); + } + } + , a); + } + + /** + * Returns an associated value with the given key in the list of pairs. + * + * @param e The test for equality on keys. + * @param x The list of pairs to search. + * @param a The key value to find the associated value of. + * @return An associated value with the given key in the list of pairs. + */ + public static <A, B> Option<B> lookup(final Equal<A> e, final List<P2<A, B>> x, final A a) { + return x.find(new F<P2<A, B>, Boolean>() { + public Boolean f(final P2<A, B> p) { + return e.eq(p._1(), a); + } + }).map(P2.<A, B>__2()); + } + + /** + * Returns a partially applied version of {@link #lookup(Equal, List, Object)}. + * + * @param e The test for equality on keys. + * @return A partially applied version of {@link #lookup(Equal , List, Object)}. + */ + public static <A, B> F2<List<P2<A, B>>, A, Option<B>> lookup(final Equal<A> e) { + return new F2<List<P2<A, B>>, A, Option<B>>() { + public Option<B> f(final List<P2<A, B>> x, final A a) { + return lookup(e, x, a); + } + }; + } + + /** + * Provides a first-class version of bind() + * + * @return The bind function for lists. + */ + public static <A, B> F<F<A, List<B>>, F<List<A>, List<B>>> bind_() { + return curry(new F2<F<A, List<B>>, List<A>, List<B>>() { + public List<B> f(final F<A, List<B>> f, final List<A> as) { + return as.bind(f); + } + }); + } + + /** + * Provides a first-class version of map() + * + * @return The map function for lists. + */ + public static <A, B> F<F<A, B>, F<List<A>, List<B>>> map_() { + return curry(new F2<F<A, B>, List<A>, List<B>>() { + public List<B> f(final F<A, B> f, final List<A> as) { + return as.map(f); + } + }); + } + + /** + * Turn a list of functions into a function returning a list. + * + * @param fs The list of functions to sequence into a single function that returns a list. + * @return A function that, when given an argument, applies all the functions in the given list to it + * and returns a list of the results. + */ + public static <A, B> F<B, List<A>> sequence_(final List<F<B, A>> fs) { + return fs.foldRight(Function.<A, List<A>, List<A>, B>lift(List.<A>cons()), Function + .<B, List<A>>constant(List.<A>nil())); + } + + /** + * Provides a first-class version of foldLeft. + * + * @return The left fold function for lists. + */ + public static <A, B> F<F<B, F<A, B>>, F<B, F<List<A>, B>>> foldLeft() { + return curry(new F3<F<B, F<A, B>>, B, List<A>, B>() { + public B f(final F<B, F<A, B>> f, final B b, final List<A> as) { + return as.foldLeft(f, b); + } + }); + } + + /** + * Provides a first-class version of take. + * + * @return First-class version of take. + */ + public static <A> F<Integer, F<List<A>, List<A>>> take() { + return curry(new F2<Integer, List<A>, List<A>>() { + public List<A> f(final Integer n, final List<A> as) { + return as.take(n); + } + }); + } + + /** + * Takes the given iterable to a list. + * + * @param i The iterable to take to a list. + * @return A list from the given iterable. + */ + public static <A> List<A> iterableList(final Iterable<A> i) { + final Buffer<A> bs = empty(); + + for (final A a : i) + bs.snoc(a); + + return bs.toList(); + } + + + /** + * A mutable, singly linked list. This structure should be used <em>very</em> sparingly, in favour + * of the {@link List immutable singly linked list structure}. + */ + public static final class Buffer<A> implements Iterable<A> { + private List<A> start = nil(); + private Cons<A> tail; + private boolean exported; + + /** + * Returns an iterator for this buffer. This method exists to permit the use in a <code>for</code>-each loop. + * + * @return A iterator for this buffer. + */ + public Iterator<A> iterator() { + return start.iterator(); + } + + /** + * Appends (snoc) the given element to this buffer to produce a new buffer. + * + * @param a The element to append to this buffer. + * @return A new buffer with the given element appended. + */ + public Buffer<A> snoc(final A a) { + if (exported) + copy(); + + final Cons<A> t = new Cons<A>(a, List.<A>nil()); + + if (tail == null) + start = t; + else + tail.tail(t); + + tail = t; + + return this; + } + + /** + * Appends the given buffer to this buffer. + * + * @param as The buffer to append to this one. + * @return A new buffer that has appended the given buffer. + */ + public Buffer<A> append(final List<A> as) { + for (List<A> xs = as; xs.isNotEmpty(); xs = xs.tail()) + snoc(xs.head()); + + return this; + } + + /** + * Returns an immutable list projection of this buffer. Modifications to the underlying buffer + * will <em>not</em> be reflected in returned lists. + * + * @return An immutable list projection of this buffer. + */ + public List<A> toList() { + exported = !start.isEmpty(); + return start; + } + + /** + * Projects an immutable collection of this buffer. + * + * @return An immutable collection of this buffer. + */ + public Collection<A> toCollection() { + return start.toCollection(); + } + + /** + * An empty buffer. + * + * @return An empty buffer. + */ + public static <A> Buffer<A> empty() { + return new Buffer<A>(); + } + + /** + * Constructs a buffer from the given list. + * + * @param as The list to construct a buffer with. + * @return A buffer from the given list. + */ + public static <A> Buffer<A> fromList(final List<A> as) { + final Buffer<A> b = new Buffer<A>(); + + for (List<A> xs = as; xs.isNotEmpty(); xs = xs.tail()) + b.snoc(xs.head()); + + return b; + } + + /** + * Takes the given iterable to a buffer. + * + * @param i The iterable to take to a buffer. + * @return A buffer from the given iterable. + */ + public static <A> Buffer<A> iterableBuffer(final Iterable<A> i) { + final Buffer<A> b = empty(); + + for (final A a : i) + b.snoc(a); + + return b; + } + + @SuppressWarnings({"ObjectEquality"}) + private void copy() { + List<A> s = start; + final Cons<A> t = tail; + start = nil(); + exported = false; + while (s != t) { + snoc(s.head()); + s = s.tail(); + } + + if (t != null) + snoc(t.head()); + } + } + + /** + * Perform an equality test on this list which delegates to the .equals() method of the member instances. + * This is implemented with Equal.listEqual using the anyEqual rule. + * + * @param obj the other object to check for equality against. + * @return true if this list is equal to the provided argument + */ + //Suppress the warning for cast to <code>List<A></code> because the type is checked in the previous line. + @SuppressWarnings({ "unchecked" }) + @Override public boolean equals( final Object obj ) { + if ( obj == null || !( obj instanceof List ) ) { return false; } + + //Casting to List<A> here does not cause a runtime exception even if the type arguments don't match. + //The cast is done to avoid the compiler warning "raw use of parameterized class 'List'" + return Equal.listEqual( Equal.<A>anyEqual() ).eq( this, (List<A>) obj ); + } + + /** + * Compute the hash code from this list as a function of the hash codes of its members. + * Delegates to Hash.listHash, using the anyHash() rule, which uses the hash codes of the contents. + * + * @return the hash code for this list. + */ + @Override public int hashCode() { + return Hash.listHash( Hash.<A>anyHash() ).hash( this ); + } + + /** + * Obtain a string representation of this list using the toString implementations of the members. Uses Show.listShow with F2 argument and may + * not be very performant. + * + * @return a String representation of the list + */ + @Override public String toString() { + return Show.listShow( Show.<A>anyShow() ).show( this ).foldLeft( new F2<String, Character, String>() { + @Override public String f( final String s, final Character c ) { + return s + c; + } + }, "" ); + } +}