package fj.data; import static fj.Bottom.error; import fj.Equal; import fj.F2Functions; import fj.Hash; import fj.Monoid; import fj.Ord; import fj.Ordering; import fj.P; import fj.P1; import fj.Semigroup; import fj.Show; import fj.Unit; import fj.P2; import fj.F0; import fj.F; import fj.F2; import fj.Function; import static fj.Function.*; 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.data.optic.Optional.optional; import static fj.data.optic.Prism.prism; import static fj.data.vector.V.v; import static fj.function.Booleans.not; import static fj.Ordering.GT; import static fj.Ord.intOrd; import fj.control.Trampoline; import fj.control.parallel.Promise; import fj.control.parallel.Strategy; import fj.data.optic.Optional; import fj.data.optic.PTraversal; import fj.data.optic.Prism; import fj.data.optic.Traversal; import fj.data.vector.V2; 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((i, a) -> 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. * @deprecated As of release 4.5, use {@link #uncons} * * @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. */ @Deprecated public final <B> B list(final B nil, final F<A, F<List<A>, B>> cons) { return uncons(uncurryF2(cons), nil); } public final <B> B uncons(final F2<A, List<A>, B> cons, final B nil) { return isEmpty() ? nil : cons.f(head(), 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 F0<A> a) { return isEmpty() ? a.f() : 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 F0<List<A>> as) { return isEmpty() ? as.f() : tail(); } /** * Returns an option projection of this list; <code>None</code> if empty, or the first element in * <code>Some</code>. Equivalent to {@link #headOption()}. * @deprecated As of release 4.5, use {@link #headOption()} * @return An option projection of this list. */ @Deprecated public final Option<A> toOption() { return headOption(); } /** * Returns the head of the list, if any. Equivalent to {@link #toOption()} . * * @return The optional head of the list. */ public final Option<A> headOption() { return isEmpty() ? Option.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 F0<X> x) { return isEmpty() ? Either.left(x.f()) : Either.right(head()); } /** * Returns a stream projection of this list. * * @return A stream projection of this list. */ public final Stream<A> toStream() { return isEmpty() ? Stream.nil() : Stream.cons(head(), () -> tail().toStream()); } /** * Returns a array projection of this list. * * @return A array projection of this list. */ @SuppressWarnings("unchecked") public final Array<A> toArray() { return mkArray(toArrayObject()); } public final Object[] toArrayObject() { final int length = length(); 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 a; } /** * To be removed in future release: * affectation of the result of this method to a non generic array * will result in runtime error (ClassCastException). * * @deprecated As of release 4.6, use {@link #array(Class)}. */ @SuppressWarnings("unchecked") @Deprecated public final A[] toJavaArray() { return (A[]) toArrayObject(); } /** * 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, 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, 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(b.toList(), xs); } return p(b.toList(), List.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(a -> !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((as, bs) -> 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); } /** * Traverses through the List with the given function * * @param f The function that produces Option value * @return none if applying f returns none to any element of the list or f mapped list in some . */ public final <B> Option<List<B>> traverseOption(final F<A, Option<B>> f) { return foldRight( (a, obs) -> f.f(a).bind(o -> obs.map(os -> os.cons(o))), some(List.nil()) ); } /** * Traverse through the List with given function. * * @param f The function that produces Either value. * @return error in left or f mapped list in right. */ public final <B, E> Either<E, List<B>> traverseEither(final F<A, Either<E, B>> f) { return foldRight( (a, acc) -> f.f(a).right().bind(e -> acc.right().map(es -> es.cons(e))), Either.right(List.nil()) ); } public final <B> Stream<List<B>> traverseStream(final F<A, Stream<B>> f) { return foldRight( (a, acc) -> f.f(a).bind(s -> acc.map(ss -> ss.cons(s))), Stream.nil() ); } public final <B> P1<List<B>> traverseP1(final F<A, P1<B>> f){ return foldRight( (a, acc) -> f.f(a).bind(b -> acc.map(bs -> bs.cons(b))), p(List.nil()) ); } public final <B> IO<List<B>> traverseIO(F<A, IO<B>> f) { return this.foldRight( (a, acc) -> IOFunctions.bind(f.f(a), b -> IOFunctions.map(acc, bs -> bs.cons(b))), IOFunctions.unit(List.nil()) ); } public final <C, B> F<C, List<B>> traverseF(F<A, F<C, B>> f) { return this.foldRight( (a, acc) -> Function.bind(acc, (bs) -> Function.compose(bs::cons, f.f(a))), constant(List.nil()) ); } public final <B> Trampoline<List<B>> traverseTrampoline(final F<A, Trampoline<B>> f) { return foldRight( (a, acc) -> f.f(a).bind(b -> acc.map(bs -> bs.cons(b))), Trampoline.pure(List.nil())); } public final <B> Promise<List<B>> traversePromise(final F<A, Promise<B>> f) { return foldRight( (a, acc) -> f.f(a).bind(b -> acc.fmap(bs -> bs.cons(b))), Promise.promise(Strategy.idStrategy(), p(List.nil()))); } public final <B> List<List<B>> traverseList(final F<A, List<B>> f) { return foldRight( (a, acc) -> f.f(a).bind(b -> acc.map(bs -> bs.cons(b))), single(List.nil())); } public final <E, B> Validation<E, List<B>> traverseValidation(Semigroup<E> s, final F<A, Validation<E, B>> f) { return Validation.sequence(s, map(f)); } public final <B> V2<List<B>> traverseV2(final F<A, V2<B>> f) { return foldRight( (a, acc) -> acc.apply(f.f(a).<F<List<B>, List<B>>> map(e -> es -> es.cons(e))), v(List.nil(), List.nil())); } /** * 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(this::map); } /** * 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).prependToList(as); } /** * Performs a right-fold reduction across this list. * * @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 foldRight(uncurryF2(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 reverse().foldLeft(flip(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(P.lazy(() -> 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) { return foldLeft(uncurryF2(f), b); } /** * 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) { B x = b; for (List<A> xs = this; !xs.isEmpty(); xs = xs.tail()) { x = f.f(x, xs.head()); } return x; } /** * 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) { if (isEmpty()) throw error("Undefined: foldLeft1 on empty list"); return tail().foldLeft(f, head()); } /** * 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) { return foldLeft1(uncurryF2(f)); } /** * 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((as, a) -> cons(a, as), 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) { Buffer<A> result = empty(); List<A> list = this; int index = i; while (index > 0 && list.isNotEmpty()) { result.snoc(list.head()); list = list.tail(); index--; } return result.toList(); } /** * 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) { List<A> xs = this; for (int c = 0; 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) { int c = 0; List<A> first = List.nil(); List<A> second = nil(); for (List<A> xs = this; xs.isNotEmpty(); xs = xs.tail()) { final A h = xs.head(); if (c < i) { first = first.cons(h); } else { second = second.cons(h); } c++; } return p(first.reverse(), second.reverse()); } /** * 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(as -> as.isEmpty() ? Option.none() : some(as.splitAt(n)), this); } /** * Partitions the list into a tuple where the first element contains the * items that satisfy the the predicate f and the second element contains the * items that does not. The relative order of the elements in the returned tuple * is the same as the original list. * * @param f Predicate function. */ public final P2<List<A>, List<A>> partition(F<A, Boolean> f) { P2<List<A>, List<A>> p2 = foldLeft((acc, a) -> f.f(a) ? p(acc._1().cons(a), acc._2()) : p(acc._1(), acc._2().cons(a)), p(nil(), nil()) ); return p(p2._1().reverse(), p2._2().reverse()); } /** * 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.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.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 { 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.isLessThanOrEqualTo(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().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((as, bs, f) -> 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(List::zip); } /** * 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()), a -> i -> 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(), tail().bind(a2 -> list(a, a2))); } /** * 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.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(a -> !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.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 List::head; } /** * Reutrns the tail of the list, if any. * @return The optional tail of the list. */ public final Option<List<A>> tailOption() { return isEmpty() ? none() : some(tail()); } /** * 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 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 traverseOption(f); } /** * 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((a, bs) -> f.f(a).bind(b -> bs.map(bbs -> bbs.cons(b))), Trampoline.pure(List.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(ys.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.contramap(List.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()} (ie. Object#hasCode). * This is not safe and therefore this method is deprecated. * * @param keyFunction The function to select the keys for the map. * @return A TreeMap containing the keys with the accumulated list of matched elements. * * @deprecated As of release 4.7, use {@link #groupBy(F, Ord)} */ @Deprecated 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, 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()} (ie. Object#hasCode). * This is not safe and therefore this method is deprecated. * * @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. * * @deprecated As of release 4.7, use {@link #groupBy(F, F, Ord)} */ @Deprecated 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.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(), 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) { java.util.TreeMap<B, D> buffer = new java.util.TreeMap<>(keyOrd.toComparator()); foreachDoEffect(element -> { final B key = keyFunction.f(element); final C value = valueFunction.f(element); buffer.put(key, buffer.containsKey(key) ? groupingAcc.f(value, buffer.get(key)) : groupingAcc.f(value, groupingIdentity)); }); return TreeMap.fromMutableMap(keyOrd, buffer); } /** * 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 final boolean allEqual(final Equal<A> eq) { return isEmpty() || tail().isEmpty() || eq.eq(head(), tail().head()) && tail().allEqual(eq); } public final boolean isPrefixOf(final Equal<A> eq, final List<A> xs) { final Iterator<A> i = iterator(); final Iterator<A> j = xs.iterator(); while (i.hasNext() && j.hasNext()) { if (!eq.eq(i.next(), j.next())) { return false; } } return !i.hasNext(); } public final boolean isSuffixOf(final Equal<A> eq, final List<A> xs) { final Iterator<A> i = iterator(); final Iterator<A> j = xs.drop(xs.length() - length()).iterator(); while (i.hasNext() && j.hasNext()) { if (!eq.eq(i.next(), j.next())) { return false; } } return !i.hasNext(); } /** * First-class length. * * @return A function that gets the length of a given list. */ public static <A> F<List<A>, Integer> length_() { return List::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 maximum element in this list according to the given ordering. * * @param o An ordering for the elements of the list. * @return The optional maximum element in this list according to the given ordering. */ public final Option<A> maximumOption(final Ord<A> o) { return NonEmptyList.fromList(this).map(nel -> nel.maximum(o)); } /** * 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); } /** * Returns the minimum element in this list according to the given ordering. * * @param o An ordering for the elements of the list. * @return The optional minimum element in this list according to the given ordering. */ public final Option<A> minimumOption(final Ord<A> o) { return NonEmptyList.fromList(this).map(nel -> nel.minimum(o)); } public final java.util.List<A> toJavaList() { return new java.util.LinkedList<>(toCollection()); } /** * 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<>(); 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. */ @SafeVarargs public static <A> List<A> list(final A... as) { return arrayList(as); } /** * Constructs a list from the given elements. */ @SafeVarargs public static <A> List<A> arrayList(final A... as) { return Array.array(as).toList(); } /** * Constructs a list from the given Iterable. * @deprecated As of release 4.5, use {@link #iterableList(Iterable)} */ @Deprecated public static <A> List<A> list(final Iterable<A> i) { return iterableList(i); } /** * Constructs a list from the given Iterator. * @deprecated As of release 4.5, use {@link #iteratorList(Iterator)} */ @Deprecated public static <A> List<A> list(final Iterator<A> it) { return iteratorList(it); } /** * Constructs a list from the given Iterator. */ public static <A> List<A> fromIterator(final Iterator<A> it) { return iterableList(() -> it); } /** * 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 a -> tail -> cons(a, tail); } public static <A> F2<A, List<A>, List<A>> cons_() { return List::cons; } /** * 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 tail::cons; } /** * 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 as -> 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<>(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 List::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 List::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 List::join; } /** * 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(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) { List<A> list = nil(); for (int i = 0; i < n; i++) { list = list.cons(a); } return list; } /** * 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) { final Buffer<Integer> buf = empty(); for (int i = from; i < to; i++) { buf.snoc(i); } return buf.toList(); } /** * 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 List::fromString; } /** * 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(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 List::asString; } /** * 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.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( o -> Option.iif(p2 -> p.f(o), 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(p -> e.eq(p._1(), a)).map(P2.__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 (x, a) -> 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((f, as) -> 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((f, as) -> 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.lift(List.cons()), Function .constant(List.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((f, b, as) -> 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((n, as) -> 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(); } /** * Constructs a list from the given Iterator. */ public static <A> List<A> iteratorList(final Iterator<A> it) { return iterableList(() -> it); } /** * 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 This buffer. */ public Buffer<A> snoc(final A a) { if (exported) copy(); final Cons<A> t = new Cons<>(a, List.nil()); if (tail == null) start = t; else tail.tail(t); tail = t; return this; } /** * Appends the given list to this buffer. * * @param as The list to append to this buffer. * @return This buffer. */ public Buffer<A> append(final List<A> as) { for (List<A> xs = as; xs.isNotEmpty(); xs = xs.tail()) snoc(xs.head()); return this; } /** * Prepends the elements of this buffer to the given list. * * @param as the list to which elements are prepended. */ public List<A> prependToList(final List<A> as) { if (isEmpty()) { return as; } else { if (exported) copy(); tail.tail(as); return toList(); } } /** * Returns <code>true</code> if this buffer is empty, <code>false</code> otherwise. */ public boolean isEmpty() { return start.isEmpty(); } /** * 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<>(); } /** * 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<>(); 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(); tail = null; 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 */ @Override public final boolean equals(final Object obj) { return Equal.equals0(List.class, this, obj, () -> Equal.listEqual(Equal.anyEqual())); } /** * 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 final 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 final String toString() { return Show.listShow(Show.<A>anyShow()).showS(this); } /** * True if and only if the list has one element. Runs in constant time. */ public final boolean isSingle() { return isNotEmpty() && tail().isEmpty(); } /** * Optic factory methods for a List */ public static final class Optic { private Optic() { throw new UnsupportedOperationException(); } /** * Polymorphic traversal */ public static <A, B> PTraversal<List<A>, List<B>, A, B> pTraversal() { return new PTraversal<List<A>, List<B>, A, B>() { @Override public <C> F<List<A>, F<C, List<B>>> modifyFunctionF(F<A, F<C, B>> f) { return l -> l.traverseF(f); } @Override public <L> F<List<A>, Either<L, List<B>>> modifyEitherF(F<A, Either<L, B>> f) { return l -> l.traverseEither(f); } @Override public F<List<A>, IO<List<B>>> modifyIOF(F<A, IO<B>> f) { return l -> l.traverseIO(f); } @Override public F<List<A>, Trampoline<List<B>>> modifyTrampolineF(F<A, Trampoline<B>> f) { return l -> l.traverseTrampoline(f); } @Override public F<List<A>, Promise<List<B>>> modifyPromiseF(F<A, Promise<B>> f) { return l -> l.traversePromise(f); } @Override public F<List<A>, List<List<B>>> modifyListF(F<A, List<B>> f) { return l -> l.traverseList(f); } @Override public F<List<A>, Option<List<B>>> modifyOptionF(F<A, Option<B>> f) { return l -> l.traverseOption(f); } @Override public F<List<A>, Stream<List<B>>> modifyStreamF(F<A, Stream<B>> f) { return l -> l.traverseStream(f); } @Override public F<List<A>, P1<List<B>>> modifyP1F(F<A, P1<B>> f) { return l -> l.traverseP1(f); } @Override public <E> F<List<A>, Validation<E, List<B>>> modifyValidationF(Semigroup<E> s, F<A, Validation<E, B>> f) { return l -> l.traverseValidation(s, f); } @Override public F<List<A>, V2<List<B>>> modifyV2F(F<A, V2<B>> f) { return l -> l.traverseV2(f); } @Override public <M> F<List<A>, M> foldMap(Monoid<M> monoid, F<A, M> f) { return l -> monoid.sumLeft(l.map(f)); } }; } /** * Monomorphic traversal */ public static <A> Traversal<List<A>, A> traversal() { return new Traversal<>(pTraversal()); } /** * Optional targeted on Cons head. */ public static <A> Optional<List<A>, A> head() { return optional(List::headOption, a -> l -> l.uncons((__, as) -> as.cons(a), l)); } /** * Optional targeted on Cons tail. */ public static <A> Optional<List<A>, List<A>> tail() { return optional(l -> l.uncons((__, tail) -> some(tail), none()), tail -> l -> l.uncons((h, __) -> List.cons(h, tail), l)); } /** * Nil prism */ public static <A> Prism<List<A>, Unit> nil() { return prism((List<A> l) -> l.isEmpty() ? some(unit()) : none(), constant(List.nil())); } /** * Cons prism */ public static <A> Prism<List<A>, P2<A, List<A>>> cons() { return prism(l -> l.<Option<P2<A, List<A>>>> uncons((h, tail) -> some(p(h, tail)), none()), c -> List.cons(c._1(), c._2())); } } public static final class Unsafe { } }