package fj.data;
import fj.Equal;
import fj.F0;
import fj.F3;
import fj.Hash;
import fj.Show;
import fj.F;
import fj.F2;
import fj.Function;
import fj.Monoid;
import fj.Ord;
import fj.P;
import fj.P1;
import fj.P2;
import fj.Unit;
import fj.control.parallel.Promise;
import fj.control.parallel.Strategy;
import fj.Ordering;
import fj.function.Effect1;
import java.util.*;
import static fj.Bottom.error;
import static fj.Function.*;
import static fj.P.p;
import static fj.P.p2;
import static fj.P.weakMemo;
import static fj.Unit.unit;
import static fj.control.parallel.Promise.promise;
import static fj.data.Array.mkArray;
import static fj.data.Option.none;
import static fj.data.Option.some;
import static fj.function.Booleans.not;
import static fj.Ordering.EQ;
import static fj.Ordering.GT;
import static fj.Ordering.LT;
/**
* A lazy (not yet evaluated), immutable, singly linked list.
*
* @version %build.number%
*/
public abstract class Stream<A> implements Iterable<A> {
private Stream() {
}
/**
* Returns an iterator for this stream. This method exists to permit the use in a <code>for</code>-each loop.
*
* @return A iterator for this stream.
*/
public final Iterator<A> iterator() {
return toCollection().iterator();
}
/**
* The first element of the stream or fails for the empty stream.
*
* @return The first element of the stream or fails for the empty stream.
*/
public abstract A head();
/**
* The stream without the first element or fails for the empty stream.
*
* @return The stream without the first element or fails for the empty stream.
*/
public abstract P1<Stream<A>> tail();
/**
* Returns <code>true</code> if this stream is empty, <code>false</code> otherwise.
*
* @return <code>true</code> if this stream is empty, <code>false</code> otherwise.
*/
public final boolean isEmpty() {
return this instanceof Nil;
}
/**
* Returns <code>false</code> if this stream is empty, <code>true</code> otherwise.
*
* @return <code>false</code> if this stream is empty, <code>true</code> otherwise.
*/
public final boolean isNotEmpty() {
return this instanceof Cons;
}
/**
* Performs a reduction on this stream using the given arguments. Equivalent to {@link #uncons}.
*
* @deprecated As of release 4.5, use {@link #uncons}
*
* @param nil The value to return if this stream is empty.
* @param cons The function to apply to the head and tail of this stream if it is not empty.
* @return A reduction on this stream.
*/
@Deprecated
public final <B> B stream(final B nil, final F<A, F<P1<Stream<A>>, B>> cons) {
return uncons(nil, cons);
}
/**
* Performs a reduction on this stream using the given arguments.
*
* @param nil The value to return if this stream is empty.
* @param cons The function to apply to the head and tail of this stream if it is not empty.
* @return A reduction on this stream.
*/
public final <B> B uncons(final B nil, final F<A, F<P1<Stream<A>>, B>> cons) {
return isEmpty() ? nil : cons.f(head()).f(tail());
}
/**
* Performs a right-fold reduction across this stream. This function uses O(length) stack space.
*
* @param f The function to apply on each element of the stream.
* @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<P1<B>, B>> f, final B b) {
return foldRight(uncurryF2(f), b);
}
/**
* Performs a right-fold reduction across this stream. This function uses O(length) stack space.
*
* @param f The function to apply on each element of the stream.
* @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, P1<B>, B> f, final B b) {
return isEmpty() ? b : f.f(head(), P.lazy(() -> tail()._1().foldRight(f, b)));
}
/**
* Performs a right-fold reduction across this stream. This function uses O(length) stack space.
*
* @param f The function to apply on each element of the stream.
* @param b The beginning value to start the application from.
* @return The final result after the right-fold reduction.
*/
public final <B> B foldRight1(final F<A, F<B, B>> f, final B b) {
return foldRight1(uncurryF2(f), b);
}
/**
* Performs a right-fold reduction across this stream. This function uses O(length) stack space.
*
* @param f The function to apply on each element of the stream.
* @param b The beginning value to start the application from.
* @return The final result after the right-fold reduction.
*/
public final <B> B foldRight1(final F2<A, B, B> f, final B b) {
return isEmpty() ? b : f.f(head(), tail()._1().foldRight1(f, b));
}
/**
* Performs a left-fold reduction across this stream. This function runs in constant space.
*
* @param f The function to apply on each element of the stream.
* @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 stream. This function runs in constant space.
*
* @param f The function to apply on each element of the stream.
* @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 (Stream<A> xs = this; !xs.isEmpty(); xs = xs.tail()._1())
x = f.f(x, xs.head());
return x;
}
/**
* Takes the first 2 elements of the stream 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 stream.
* @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()._1().foldLeft(f, head());
}
/**
* Takes the first 2 elements of the stream 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 stream.
* @return The final result after the left-fold reduction.
*/
public final A foldLeft1(final F<A, F<A, A>> f) {
return foldLeft1(uncurryF2(f));
}
/**
* Returns the head of this stream if there is one or the given argument if this stream is empty.
*
* @param a The argument to return if this stream is empty.
* @return The head of this stream if there is one or the given argument if this stream is empty.
*/
public final A orHead(final F0<A> a) {
return isEmpty() ? a.f() : head();
}
/**
* Returns the tail of this stream if there is one or the given argument if this stream is empty.
*
* @param as The argument to return if this stream is empty.
* @return The tail of this stream if there is one or the given argument if this stream is empty.
*/
public final P1<Stream<A>> orTail(final F0<Stream<A>> as) {
return isEmpty() ? P.lazy(as) : tail();
}
/**
* Intersperses the given value between each two elements of the stream.
*
* @param a The value to intersperse between values of the stream.
* @return A new stream with the given value between each two elements of the stream.
*/
public final Stream<A> intersperse(final A a) {
return isEmpty() ? this : cons(head(), new P1<Stream<A>>() {
public Stream<A> _1() {
return prefix(a, tail()._1());
}
public Stream<A> prefix(final A x, final Stream<A> xs) {
return xs.isEmpty() ? xs : cons(x, p(cons(xs.head(), () -> prefix(a, xs.tail()._1()))));
}
});
}
/**
* Maps the given function across this stream.
*
* @param f The function to map across this stream.
* @return A new stream after the given function has been applied to each element.
*/
public final <B> Stream<B> map(final F<A, B> f) {
return isEmpty() ? Stream.nil() : cons(f.f(head()), () -> tail()._1().map(f));
}
/**
* Provides a first-class version of the map function.
*
* @return A function that maps a given function across a given stream.
*/
public static <A, B> F<F<A, B>, F<Stream<A>, Stream<B>>> map_() {
return f -> as -> as.map(f);
}
/**
* Performs a side-effect for each element of this stream.
*
* @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 (Stream<A> xs = this; xs.isNotEmpty(); xs = xs.tail()._1())
f.f(xs.head());
return unit();
}
/**
* Performs a side-effect for each element of this stream.
*
* @param f The side-effect to perform for the given element.
*/
public final void foreachDoEffect(final Effect1<A> f) {
for (Stream<A> xs = this; xs.isNotEmpty(); xs = xs.tail()._1())
f.f(xs.head());
}
/**
* Filters elements from this stream 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 stream whose elements all match the given predicate.
*/
public final Stream<A> filter(final F<A, Boolean> f) {
final Stream<A> as = dropWhile(not(f));
return as.isNotEmpty() ? cons(as.head(), () -> as.tail()._1().filter(f)) : as;
}
/**
* Appends the given stream to this stream.
*
* @param as The stream to append to this one.
* @return A new stream that has appended the given stream.
*/
public final Stream<A> append(final Stream<A> as) {
return isEmpty() ? as : cons(head(), () -> tail()._1().append(as));
}
/**
* Appends the given stream to this stream.
*
* @param as The stream to append to this one.
* @return A new stream that has appended the given stream.
*/
public final Stream<A> append(final F0<Stream<A>> as) {
return isEmpty() ? as.f() : cons(head(), () -> tail()._1().append(as));
}
/**
* Returns a new stream of all the items in this stream that do not appear in the given stream.
*
* @param eq an equality for the items of the streams.
* @param xs a list to subtract from this stream.
* @return a stream of all the items in this stream that do not appear in the given stream.
*/
public final Stream<A> minus(final Equal<A> eq, final Stream<A> xs) {
return removeAll(compose(Monoid.disjunctionMonoid.sumLeftS(), xs.mapM(curry(eq.eq()))));
}
/**
* Filters elements from this stream 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 stream whose elements do not match the given predicate.
*/
public final Stream<A> removeAll(final F<A, Boolean> f) {
return filter(compose(not, f));
}
/**
* Turn a stream of functions into a function returning a stream.
*
* @param fs The stream of functions to sequence into a single function that returns a stream.
* @return A function that, when given an argument, applies all the functions in the given stream to it
* and returns a stream of the results.
*/
public static <A, B> F<B, Stream<A>> sequence_(final Stream<F<B, A>> fs) {
return fs.foldRight((baf, p1) -> Function.bind(baf, p1._1(), curry((a, stream) -> cons(a, p(stream)))), Function
.constant(Stream.nil()));
}
/**
* Maps the given function of arity-2 across this stream 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, Stream<C>> mapM(final F<A, F<B, C>> f) {
return sequence_(map(f));
}
/**
* Binds the given function across each element of this stream with a final join.
*
* @param f The function to apply to each element of this stream.
* @return A new stream after performing the map, then final join.
*/
public final <B> Stream<B> bind(final F<A, Stream<B>> f) {
return foldRight(h -> t -> f.f(h).append(t), nil());
}
/**
* Binds the given function across each element of this stream and the given stream with a final
* join.
*
* @param sb A given stream to bind the given function with.
* @param f The function to apply to each element of this stream and the given stream.
* @return A new stream after performing the map, then final join.
*/
public final <B, C> Stream<C> bind(final Stream<B> sb, final F<A, F<B, C>> f) {
return sb.apply(map(f));
}
/**
* Binds the given function across each element of this stream and the given stream with a final
* join.
*
* @param sb A given stream to bind the given function with.
* @param f The function to apply to each element of this stream and the given stream.
* @return A new stream after performing the map, then final join.
*/
public final <B, C> Stream<C> bind(final Stream<B> sb, final F2<A, B, C> f) {
return bind(sb, curry(f));
}
/**
* Binds the given function across each element of this stream and the given streams with a final
* join.
*
* @param sb A given stream to bind the given function with.
* @param sc A given stream to bind the given function with.
* @param f The function to apply to each element of this stream and the given streams.
* @return A new stream after performing the map, then final join.
*/
public final <B, C, D> Stream<D> bind(final Stream<B> sb, final Stream<C> sc, final F<A, F<B, F<C, D>>> f) {
return sc.apply(bind(sb, f));
}
/**
* Binds the given function across each element of this stream and the given streams with a final
* join.
*
* @param sb A given stream to bind the given function with.
* @param sc A given stream to bind the given function with.
* @param sd A given stream to bind the given function with.
* @param f The function to apply to each element of this stream and the given streams.
* @return A new stream after performing the map, then final join.
*/
public final <B, C, D, E> Stream<E> bind(final Stream<B> sb, final Stream<C> sc, final Stream<D> sd,
final F<A, F<B, F<C, F<D, E>>>> f) {
return sd.apply(bind(sb, sc, f));
}
/**
* Binds the given function across each element of this stream and the given streams with a final
* join.
*
* @param sb A given stream to bind the given function with.
* @param sc A given stream to bind the given function with.
* @param sd A given stream to bind the given function with.
* @param se A given stream to bind the given function with.
* @param f The function to apply to each element of this stream and the given streams.
* @return A new stream after performing the map, then final join.
*/
public final <B, C, D, E, F$> Stream<F$> bind(final Stream<B> sb, final Stream<C> sc, final Stream<D> sd,
final Stream<E> se, final F<A, F<B, F<C, F<D, F<E, F$>>>>> f) {
return se.apply(bind(sb, sc, sd, f));
}
/**
* Binds the given function across each element of this stream and the given streams with a final
* join.
*
* @param sb A given stream to bind the given function with.
* @param sc A given stream to bind the given function with.
* @param sd A given stream to bind the given function with.
* @param se A given stream to bind the given function with.
* @param sf A given stream to bind the given function with.
* @param f The function to apply to each element of this stream and the given streams.
* @return A new stream after performing the map, then final join.
*/
public final <B, C, D, E, F$, G> Stream<G> bind(final Stream<B> sb, final Stream<C> sc, final Stream<D> sd,
final Stream<E> se, final Stream<F$> sf,
final F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>> f) {
return sf.apply(bind(sb, sc, sd, se, f));
}
/**
* Binds the given function across each element of this stream and the given streams with a final
* join.
*
* @param sb A given stream to bind the given function with.
* @param sc A given stream to bind the given function with.
* @param sd A given stream to bind the given function with.
* @param se A given stream to bind the given function with.
* @param sf A given stream to bind the given function with.
* @param sg A given stream to bind the given function with.
* @param f The function to apply to each element of this stream and the given streams.
* @return A new stream after performing the map, then final join.
*/
public final <B, C, D, E, F$, G, H> Stream<H> bind(final Stream<B> sb, final Stream<C> sc, final Stream<D> sd,
final Stream<E> se, final Stream<F$> sf, final Stream<G> sg,
final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>> f) {
return sg.apply(bind(sb, sc, sd, se, sf, f));
}
/**
* Binds the given function across each element of this stream and the given streams with a final
* join.
*
* @param sb A given stream to bind the given function with.
* @param sc A given stream to bind the given function with.
* @param sd A given stream to bind the given function with.
* @param se A given stream to bind the given function with.
* @param sf A given stream to bind the given function with.
* @param sg A given stream to bind the given function with.
* @param sh A given stream to bind the given function with.
* @param f The function to apply to each element of this stream and the given streams.
* @return A new stream after performing the map, then final join.
*/
public final <B, C, D, E, F$, G, H, I> Stream<I> bind(final Stream<B> sb, final Stream<C> sc, final Stream<D> sd,
final Stream<E> se, final Stream<F$> sf, final Stream<G> sg,
final Stream<H> sh,
final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>> f) {
return sh.apply(bind(sb, sc, sd, se, sf, sg, f));
}
/**
* Performs a bind across each stream element, but ignores the element value each time.
*
* @param bs The stream to apply in the final join.
* @return A new stream after the final join.
*/
public final <B> Stream<B> sequence(final Stream<B> bs) {
final F<A, Stream<B>> c = constant(bs);
return bind(c);
}
/**
* Sequence through the Stream monad.
*
* @param io The IO stream to sequence.
* @return The stream of IOs after sequencing.
*/
public static <A> Stream<IO<A>> sequence(final IO<Stream<A>> io) {
return IOFunctions.runSafe(io).map(IOFunctions::unit);
}
/**
* Sequence through the Stream monad.
*
* @param p The lazy stream to sequence.
* @return The stream of (pre-calculated) lazy values after sequencing.
*/
public static <A> Stream<P1<A>> sequence(final F0<Stream<A>> p) {
return p.f().map(P::p);
}
/**
* Sequence through the Stream monad.
*
* @param o The optional stream to sequence.
* @return The stream of options after sequencing.
*/
public static <A> Stream<Option<A>> sequence(final Option<Stream<A>> o) {
return o.isNone() ? nil() : o.some().map(Option::some);
}
/**
* Performs function application within a stream (applicative functor pattern).
*
* @param sf The stream of functions to apply.
* @return A new stream after applying the given stream of functions through this stream.
*/
public final <B> Stream<B> apply(final Stream<F<A, B>> sf) {
return sf.bind(this::map);
}
/**
* Interleaves the given stream with this stream to produce a new stream.
*
* @param as The stream to interleave this stream with.
* @return A new stream with elements interleaved from this stream and the given stream.
*/
public final Stream<A> interleave(final Stream<A> as) {
return isEmpty() ? as : as.isEmpty() ? this : cons(head(), () -> as.interleave(tail()._1()));
}
public static <A> Stream<A> enumerationStream(Enumeration<A> e) {
if (e.hasMoreElements()) {
return cons(e.nextElement(), () -> enumerationStream(e));
} else {
return nil();
}
}
/**
* Sort this stream according to the given ordering.
*
* @param o An ordering for the elements of this stream.
* @return A new stream with the elements of this stream sorted according to the given ordering.
*/
public final Stream<A> sort(final Ord<A> o) {
return mergesort(o, map(flip(Stream.<A>cons()).f(p(Stream.nil()))));
}
// Merges a stream of individually sorted streams into a single sorted stream.
private static <A> Stream<A> mergesort(final Ord<A> o, final Stream<Stream<A>> s) {
if (s.isEmpty())
return nil();
Stream<Stream<A>> xss = s;
while (xss.tail()._1().isNotEmpty())
xss = mergePairs(o, xss);
return xss.head();
}
// Merges individually sorted streams two at a time.
private static <A> Stream<Stream<A>> mergePairs(final Ord<A> o, final Stream<Stream<A>> s) {
if (s.isEmpty() || s.tail()._1().isEmpty())
return s;
final Stream<Stream<A>> t = s.tail()._1();
return cons(merge(o, s.head(), t.head()), () -> mergePairs(o, t.tail()._1()));
}
// Merges two individually sorted streams.
private static <A> Stream<A> merge(final Ord<A> o, final Stream<A> xs, final Stream<A> ys) {
if (xs.isEmpty())
return ys;
if (ys.isEmpty())
return xs;
final A x = xs.head();
final A y = ys.head();
if (o.isGreaterThan(x, y))
return cons(y, () -> merge(o, xs, ys.tail()._1()));
return cons(x, () -> merge(o, xs.tail()._1(), ys));
}
/**
* Sort this stream according to the given ordering, using a parallel Quick Sort algorithm that uses the given
* parallelisation strategy.
*
* @param o An ordering for the elements of this stream.
* @param s A strategy for parallelising the algorithm.
* @return A new stream with the elements of this stream sorted according to the given ordering.
*/
public final Stream<A> sort(final Ord<A> o, final Strategy<Unit> s) {
return qs(o, s).claim();
}
private Promise<Stream<A>> qs(final Ord<A> o, final Strategy<Unit> s) {
if (isEmpty())
return promise(s, p(this));
else {
final F<Boolean, Boolean> id = identity();
final A x = head();
final P1<Stream<A>> xs = tail();
final Promise<Stream<A>> left = Promise.join(s, xs.map(flt(o, s, x, id)));
final Promise<Stream<A>> right = xs.map(flt(o, s, x, not))._1();
final Monoid<Stream<A>> m = Monoid.streamMonoid();
return right.fmap(m.sum(single(x))).apply(left.fmap(m.sum()));
}
}
private static <A> F<Stream<A>, Promise<Stream<A>>> qs_(final Ord<A> o, final Strategy<Unit> s) {
return xs -> xs.qs(o, s);
}
private static <A> F<Stream<A>, Promise<Stream<A>>> flt(final Ord<A> o,
final Strategy<Unit> s,
final A x,
final F<Boolean, Boolean> f) {
final F<F<A, Boolean>, F<Stream<A>, Stream<A>>> filter = filter();
final F<A, Boolean> lt = o.isLessThan(x);
return compose(qs_(o, s), filter.f(compose(f, lt)));
}
/**
* Projects an immutable collection of this stream.
*
* @return An immutable collection of this stream.
*/
public final Collection<A> toCollection() {
return new AbstractCollection<A>() {
public Iterator<A> iterator() {
return new Iterator<A>() {
private Stream<A> xs = Stream.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()._1();
return a;
}
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public int size() {
return length();
}
};
}
/**
* Returns a stream 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 stream (inclusive).
* @param to The maximum value for the stream (exclusive).
* @return A stream of integers from the given <code>from</code> value (inclusive) to the given
* <code>to</code> value (exclusive).
*/
public static Stream<Integer> range(final int from, final long to) {
return from >= to ? Stream.nil() : cons(from, () -> range(from + 1, to));
}
/**
* Constructs a stream with the given elements.
*
* @param as The elements which which to construct a stream.
* @return a new stream with the given elements.
*/
@SafeVarargs public static <A> Stream<A> stream(final A... as) {
return arrayStream(as);
}
/**
* Constructs a stream with the given elements in the Iterable. Equivalent to {@link #iterableStream(Iterable)} .
*
* @deprecated As of release 4.5, use {@link #iterableStream(Iterable)}
*/
@Deprecated
public static <A> Stream<A> stream(Iterable<A> it) {
return iterableStream(it);
}
/**
* Constructs a stream with the given elements in the Iterator. Equivalent to {@link #iteratorStream(Iterator)} .
*
* @deprecated As of release 4.5, use {@link #iteratorStream(Iterator)}
*/
@Deprecated
public static <A> Stream<A> stream(final Iterator<A> it) {
return iteratorStream(it);
}
/**
* Constructs a stream with the given elements in the Iterator.
*/
public static <A> Stream<A> iteratorStream(final Iterator<A> it) {
if (it.hasNext()) {
final A a = it.next();
return cons(a, () -> iteratorStream(it));
} else
return nil();
}
/**
* Returns a stream that is either infinite or bounded up to the maximum value of the given iterator starting at the
* given value and stepping at increments of <code>1</code>.
*
* @param e The enumerator to compute successors from.
* @param from The value to begin computing successors from.
* @return A stream that is either infinite or bounded up to the maximum value of the given iterator starting at the
* given value and stepping at increments of <code>1</code>.
*/
public static <A> Stream<A> forever(final Enumerator<A> e, final A from) {
return forever(e, from, 1L);
}
/**
* Returns a stream that is either infinite or bounded up to the maximum value of the given iterator starting at the
* given value and stepping at the given increment.
*
* @param e The enumerator to compute successors from.
* @param from The value to begin computing successors from.
* @param step The increment to step.
* @return A stream that is either infinite or bounded up to the maximum value of the given iterator starting at the
* given value and stepping at the given increment.
*/
public static <A> Stream<A> forever(final Enumerator<A> e, final A from, final long step) {
return cons(from, () -> e.plus(from, step).map(a -> forever(e, a, step)).orSome(Stream.nil()));
}
/**
* Returns a stream using the given enumerator from the given value to the other given value stepping at increments of
* <code>1</code>.
*
* @param e The enumerator to compute successors from.
* @param from The value to begin computing successors from.
* @param to The value to stop computing successors from.
* @return A stream using the given enumerator from the given value to the other given value stepping at increments of
* <code>1</code>.
*/
public static <A> Stream<A> range(final Enumerator<A> e, final A from, final A to) {
return range(e, from, to, 1L);
}
/**
* Returns a stream using the given enumerator from the given value to the other given value stepping at the given
* increment.
*
* @param e The enumerator to compute successors from.
* @param from The value to begin computing successors from.
* @param to The value to stop computing successors from.
* @param step The increment to step.
* @return A stream using the given enumerator from the given value to the other given value stepping at the given
* increment.
*/
public static <A> Stream<A> range(final Enumerator<A> e, final A from, final A to, final long step) {
final Ordering o = e.order().compare(from, to);
return o == EQ || step > 0L && o == GT || step < 0L && o == LT ? single(from) : cons(from, () -> join(e.plus(from, step).filter(a -> !(o == LT
? e.order().isLessThan(to, a)
: e.order().isGreaterThan(to, a))).map(a1 -> range(e, a1, to, step)).toStream()));
}
/**
* Returns an infinite stream of integers from the given <code>from</code> value (inclusive).
*
* @param from The minimum value for the stream (inclusive).
* @return A stream of integers from the given <code>from</code> value (inclusive).
*/
public static Stream<Integer> range(final int from) {
return cons(from, () -> range(from + 1));
}
/**
* Returns a first-class version of the filter function.
*
* @return a function that filters a given stream using a given predicate.
*/
public static <A> F<F<A, Boolean>, F<Stream<A>, Stream<A>>> filter() {
return curry((f, as) -> as.filter(f));
}
/**
* Zips this stream with the given stream of functions, applying each function in turn to the
* corresponding element in this stream to produce a new stream. If this stream and the given stream
* have different lengths, then the longer stream is normalised so this function never fails.
*
* @param fs The stream of functions to apply to this stream.
* @return A new stream with a length the same as the shortest of this stream and the given stream.
*/
public final <B> Stream<B> zapp(final Stream<F<A, B>> fs) {
return fs.isEmpty() || isEmpty() ? Stream.nil() :
cons(fs.head().f(head()), () -> tail()._1().zapp(fs.tail()._1()));
}
/**
* Zips this stream with the given stream using the given function to produce a new stream. If
* this stream and the given stream have different lengths, then the longer stream is normalised
* so this function never fails.
*
* @param bs The stream to zip this stream with.
* @param f The function to zip this stream and the given stream with.
* @return A new stream with a length the same as the shortest of this stream and the given
* stream.
*/
public final <B, C> Stream<C> zipWith(final Stream<B> bs, final F<A, F<B, C>> f) {
return bs.zapp(zapp(repeat(f)));
}
/**
* Zips this stream with the given stream using the given function to produce a new stream. If
* this stream and the given stream have different lengths, then the longer stream is normalised
* so this function never fails.
*
* @param bs The stream to zip this stream with.
* @param f The function to zip this stream and the given stream with.
* @return A new stream with a length the same as the shortest of this stream and the given
* stream.
*/
public final <B, C> Stream<C> zipWith(final Stream<B> bs, final F2<A, B, C> f) {
return zipWith(bs, curry(f));
}
/**
* Partially-applied version of zipWith.
* Returns a function that zips a given stream with this stream using the given function.
*
* @param f The function to zip this stream and a given stream with.
* @return A function that zips a given stream with this stream using the given function.
*/
public final <B, C> F<Stream<B>, Stream<C>> zipWith(final F<A, F<B, C>> f) {
return stream -> zipWith(stream, f);
}
/**
* Zips this stream with the given stream to produce a stream of pairs. If this stream and the
* given stream have different lengths, then the longer stream is normalised so this function
* never fails.
*
* @param bs The stream to zip this stream with.
* @return A new stream with a length the same as the shortest of this stream and the given
* stream.
*/
public final <B> Stream<P2<A, B>> zip(final Stream<B> bs) {
final F<A, F<B, P2<A, B>>> __2 = p2();
return zipWith(bs, __2);
}
/**
* Zips this stream with the index of its element as a pair.
*
* @return A new stream with the same length as this stream.
*/
public final Stream<P2<A, Integer>> zipIndex() {
return zipWith(range(0), (F2<A, Integer, P2<A, Integer>>) P::p);
}
/**
* Returns an either projection of this stream; 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 stream is empty.
* @return An either projection of this stream.
*/
public final <X> Either<X, A> toEither(final F0<X> x) {
return isEmpty() ? Either.left(x.f()) : Either.right(head());
}
/**
* Returns an option projection of this stream; <code>None</code> if empty, or the first element
* in <code>Some</code>.
*
* @return An option projection of this stream.
*/
public final Option<A> toOption() {
return isEmpty() ? Option.none() : some(head());
}
/**
* 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)}.
*/
@Deprecated
public final A[] toJavaArray() {
@SuppressWarnings("unchecked")
final A[] array = (A[]) new Object[length()];
int i = 0;
for (A a: this) {
array[i] = a;
i++;
}
return array;
}
/**
* Returns a list projection of this stream.
*
* @return A list projection of this stream.
*/
public final List<A> toList() {
List.Buffer<A> buf = List.Buffer.empty();
foreachDoEffect(buf::snoc);
return buf.toList();
}
/**
* Returns a java.util.List projection of this stream.
*/
public final java.util.List<A> toJavaList() {
return new java.util.LinkedList<>(toCollection());
}
/**
* Returns a array projection of this stream.
*
* @return A array projection of this stream.
*/
@SuppressWarnings("unchecked")
public final Array<A> toArray() {
final int l = length();
final Object[] a = new Object[l];
Stream<A> x = this;
for (int i = 0; i < l; i++) {
a[i] = x.head();
x = x.tail()._1();
}
return mkArray(a);
}
/**
* Returns a array projection of this stream.
*
* @param c The class type of the array to return.
* @return A array projection of this stream.
*/
@SuppressWarnings({"unchecked", "UnnecessaryFullyQualifiedName"})
public final Array<A> toArray(final Class<A[]> c) {
final A[] a = (A[]) java.lang.reflect.Array.newInstance(c.getComponentType(), length());
int i = 0;
for (final A x : this) {
a[i] = x;
i++;
}
return Array.array(a);
}
/**
* Returns an array from this stream.
*
* @param c The class type of the array to return.
* @return An array from this stream.
*/
public final A[] array(final Class<A[]> c) {
return toArray(c).array(c);
}
/**
* Prepends (cons) the given element to this stream to product a new stream.
*
* @param a The element to prepend.
* @return A new stream with the given element at the head.
*/
public final Stream<A> cons(final A a) {
return new Cons<>(a, () -> Stream.this);
}
/**
* Returns a string from the given stream of characters. The inverse of this function is {@link
* #fromString(String)}.
*
* @param cs The stream of characters to produce the string from.
* @return A string from the given stream of characters.
*/
public static String asString(final Stream<Character> cs) {
StringBuilder sb = new StringBuilder();
cs.foreachDoEffect(sb::append);
return sb.toString();
}
/**
* Returns a stream of characters from the given string. The inverse of this function is {@link
* #asString(Stream)}.
*
* @param s The string to produce the stream of characters from.
* @return A stream of characters from the given string.
*/
public static Stream<Character> fromString(final String s) {
return LazyString.str(s).toStream();
}
/**
* Append the given element to this stream to product a new stream.
*
* @param a The element to append.
* @return A new stream with the given element at the end.
*/
public final Stream<A> snoc(final A a) {
return snoc(p(a));
}
/**
* Append the given element to this stream to produce a new stream.
*
* @param a The element to append.
* @return A new stream with the given element at the end.
*/
public final Stream<A> snoc(final F0<A> a) {
return append(() -> single(a.f()));
}
/**
* Returns the first <code>n</code> elements from the head of this stream.
*
* @param n The number of elements to take from this stream.
* @return The first <code>n</code> elements from the head of this stream.
*/
public final Stream<A> take(final int n) {
return n <= 0 || isEmpty() ?
Stream.nil() :
cons(head(), () -> n <= 1 ? Stream.nil() : tail()._1().take(n - 1));
}
/**
* Drops the given number of elements from the head of this stream if they are available.
*
* @param i The number of elements to drop from the head of this stream.
* @return A stream with a length the same, or less than, this stream.
*/
public final Stream<A> drop(final int i) {
Stream<A> xs = this;
for (int c = 0; xs.isNotEmpty() && c < i; xs = xs.tail()._1())
c++;
return xs;
}
/**
* Returns the first elements of the head of this stream that match the given predicate function.
*
* @param f The predicate function to apply on this stream until it finds an element that does not
* hold, or the stream is exhausted.
* @return The first elements of the head of this stream that match the given predicate function.
*/
public final Stream<A> takeWhile(final F<A, Boolean> f) {
return isEmpty() ?
this :
f.f(head()) ?
cons(head(), () -> tail()._1().takeWhile(f)) :
Stream.nil();
}
/**
* Traversable instance of Stream for IO.
*
* @return traversed value
*/
public final <B> IO<Stream<B>> traverseIO(F<A, IO<B>> f) {
return this.foldRight1((a, acc) ->
IOFunctions.bind(acc, (Stream<B> bs) ->
IOFunctions.map(f.f(a), bs::cons)), IOFunctions.unit(Stream.nil()));
}
/**
* Traversable instance of Stream for Option.
*
* @return traversed value
*/
public final <B> Option<Stream<B>> traverseOption(F<A, Option<B>> f) {
return this.foldRight1((a, acc) -> acc.bind(bs -> f.f(a).map(bs::cons)), some(Stream.nil()));
}
/**
* Removes elements from the head of this stream that do not match the given predicate function
* until an element is found that does match or the stream is exhausted.
*
* @param f The predicate function to apply through this stream.
* @return The stream whose first element does not match the given predicate function.
*/
public final Stream<A> dropWhile(final F<A, Boolean> f) {
Stream<A> as;
//noinspection StatementWithEmptyBody
for (as = this; !as.isEmpty() && f.f(as.head()); as = as.tail()._1()) ;
return as;
}
/**
* Returns a tuple where the first element is the longest prefix of this stream that satisfies
* the given predicate and the second element is the remainder of the stream.
*
* @param p A predicate to be satisfied by a prefix of this stream.
* @return A tuple where the first element is the longest prefix of this stream that satisfies
* the given predicate and the second element is the remainder of the stream.
*/
public final P2<Stream<A>, Stream<A>> span(final F<A, Boolean> p) {
if (isEmpty())
return p(this, this);
else if (p.f(head())) {
final P1<P2<Stream<A>, Stream<A>>> yszs = P.lazy(() -> tail()._1().span(p));
return P.lazy(
() -> cons(head(), yszs.map(P2.__1())),
() -> yszs._1()._2()
);
} else
return p(Stream.nil(), this);
}
/**
* Returns a new stream resulting from replacing all elements that match the given predicate with the given element.
*
* @param p The predicate to match replaced elements.
* @param a The element with which to replace elements.
* @return A new stream resulting from replacing all elements that match the given predicate with the given element.
*/
public final Stream<A> replace(final F<A, Boolean> p, final A a) {
if (isEmpty())
return nil();
else {
final P2<Stream<A>, Stream<A>> s = span(p);
return s._1().append(cons(a, () -> s._2().tail()._1().replace(p, a)));
}
}
/**
* Returns a tuple where the first element is the longest prefix of this stream that does not satisfy
* the given predicate and the second element is the remainder of the stream.
*
* @param p A predicate not to be satisfied by a prefix of this stream.
* @return A tuple where the first element is the longest prefix of this stream that does not satisfy
* the given predicate and the second element is the remainder of the stream.
*/
public final P2<Stream<A>, Stream<A>> split(final F<A, Boolean> p) {
return span(compose(not, p));
}
/**
* Reverse this stream in constant stack space.
*
* @return A new stream that is the reverse of this one.
*/
public final Stream<A> reverse() {
return foldLeft((as, a) -> cons(a, () -> as), Stream.nil());
}
/**
* Get the last element of this stream. Undefined for infinite streams.
*
* @return The last element in this stream, if there is one.
*/
public final A last() {
return reverse().head();
}
/**
* The length of this stream. This function will not terminate for an infinite stream.
*
* @return The length of this stream.
*/
public final int length() {
// we're using an iterative approach here as the previous implementation (toList().length()) took
// very long even for some 10000 elements.
Stream<A> xs = this;
int i = 0;
while (!xs.isEmpty()) {
xs = xs.tail()._1();
i += 1;
}
return i;
}
/**
* 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)
throw error("index " + i + " out of range on stream");
else {
Stream<A> xs = this;
for (int c = 0; c < i; c++) {
if (xs.isEmpty())
throw error("index " + i + " out of range on stream");
xs = xs.tail()._1();
}
if (xs.isEmpty())
throw error("index " + i + " out of range on stream");
return xs.head();
}
}
/**
* Returns <code>true</code> if the predicate holds for all of the elements of this stream,
* <code>false</code> otherwise (<code>true</code> for the empty stream).
*
* @param f the predicate function to test on each element of this stream.
* @return <code>true</code> if the predicate holds for all of the elements of this stream,
* <code>false</code> otherwise.
*/
public final boolean forall(final F<A, Boolean> f) {
for (final A a : this) {
if (!f.f(a)) return false;
}
return true;
}
@Override
public final boolean equals(Object other) {
return Equal.equals0(Stream.class, this, other, () -> Equal.streamEqual(Equal.anyEqual()));
}
@Override
public final int hashCode() {
return Hash.streamHash(Hash.<A>anyHash()).hash(this);
}
@Override
public final String toString() {
return toStringLazy();
}
public final String toStringLazy() {
return isEmpty() ? "Nil()" : "Cons(" + Show.<A>anyShow().showS(head()) + ", ?)";
}
public final String toStringEager() {
return Show.streamShow(Show.<A>anyShow()).showS(this);
}
/**
* Returns <code>true</code> if the predicate holds for at least one of the elements of this
* stream, <code>false</code> otherwise (<code>false</code> for the empty stream).
*
* @param f The predicate function to test on the elements of this stream.
* @return <code>true</code> if the predicate holds for at least one of the elements of this
* stream.
*/
public final boolean exists(final F<A, Boolean> f) {
return dropWhile(not(f)).isNotEmpty();
}
/**
* 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 stream.
* @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 (Stream<A> as = this; as.isNotEmpty(); as = as.tail()._1()) {
if (f.f(as.head()))
return some(as.head());
}
return none();
}
/**
* Binds the given function across the stream of substreams of this stream.
*
* @param k A function to bind across this stream and its substreams.
* @return a new stream of the results of applying the given function to this stream and its substreams.
*/
public final <B> Stream<B> cobind(final F<Stream<A>, B> k) {
return substreams().map(k);
}
/**
* Returns a stream of the suffixes of this stream. A stream is considered to be a suffix of itself in this context.
*
* @return a stream of the suffixes of this stream, starting with the stream itself.
*/
public final Stream<Stream<A>> tails() {
return isEmpty() ? Stream.nil() : cons(this, () -> tail()._1().tails());
}
/**
* Returns a stream of all prefixes of this stream. A stream is considered a prefix of itself in tnis context.
*
* @return a stream of the prefixes of this stream, starting with the stream itself.
*/
public final Stream<Stream<A>> inits() {
final Stream<Stream<A>> nil = cons(Stream.nil(), Stream::nil);
return isEmpty() ? nil : nil.append(() -> tail()._1().inits().map(Stream.<A>cons_().f(head())));
}
/**
* Returns a stream of all infixes of this stream. A stream is considered to contain itself.
*
* @return a stream of the infixes of this stream.
*/
public final Stream<Stream<A>> substreams() {
return tails().bind(Stream::inits);
}
/**
* Returns the position of the first element matching the given predicate, if any.
*
* @param p A predicate to match.
* @return the position of the first element matching the given predicate, if any.
*/
public final Option<Integer> indexOf(final F<A, Boolean> p) {
return zipIndex().find(p2 -> p.f(p2._1())).map(P2.__2());
}
/**
* Applies a stream of comonadic functions to this stream, returning a stream of values.
*
* @param fs A stream of comonadic functions to apply to this stream.
* @return A new stream of the results of applying the stream of functions to this stream.
*/
public final <B> Stream<B> sequenceW(final Stream<F<Stream<A>, B>> fs) {
return fs.isEmpty()
? Stream.nil()
: cons(fs.head().f(this), () -> sequenceW(fs.tail()._1()));
}
/**
* Converts this stream to a function of natural numbers.
*
* @return A function from natural numbers to values with the corresponding position in this stream.
*/
public final F<Integer, A> toFunction() {
return this::index;
}
/**
* Converts a function of natural numbers to a stream.
*
* @param f The function to convert to a stream.
* @return A new stream of the results of the given function applied to the natural numbers, starting at 0.
*/
public static <A> Stream<A> fromFunction(final F<Natural, A> f) {
return fromFunction(Enumerator.naturalEnumerator, f, Natural.ZERO);
}
/**
* Converts a function of an enumerable type to a stream of the results of that function,
* starting at the given index.
*
* @param e An enumerator for the domain of the function.
* @param f The function to convert to a stream.
* @param i The index into the function at which to begin the stream.
* @return A new stream of the results of the given function applied to the values of the given enumerator,
* starting at the given value.
*/
public static <A, B> Stream<A> fromFunction(final Enumerator<B> e, final F<B, A> f, final B i) {
return cons(f.f(i), () -> {
final Option<B> s = e.successor(i);
return s.isSome()
? fromFunction(e, f, s.some())
: Stream.nil();
});
}
/**
* Transforms a stream of pairs into a stream of first components and a stream of second components.
*
* @param xs The stream of pairs to transform.
* @return A stream of first components and a stream of second components.
*/
public static <A, B> P2<Stream<A>, Stream<B>> unzip(final Stream<P2<A, B>> xs) {
return xs.foldRight((p, ps) -> {
final P2<Stream<A>, Stream<B>> pp = ps._1();
return p(cons(p._1(), p(pp._1())), cons(p._2(), p(pp._2())));
}, p(Stream.nil(), Stream.nil()));
}
/**
* A first-class version of the zipWith function.
*
* @return a function that zips two given streams with a given function.
*/
public static <A, B, C> F<Stream<A>, F<Stream<B>, F<F<A, F<B, C>>, Stream<C>>>> zipWith() {
return curry((F3<Stream<A>, Stream<B>, F<A, F<B, C>>, Stream<C>>) Stream::zipWith);
}
private static final class Nil<A> extends Stream<A> {
public A head() {
throw error("head on empty stream");
}
public P1<Stream<A>> tail() {
throw error("tail on empty stream");
}
}
private static final class Cons<A> extends Stream<A> {
private final A head;
private final P1<Stream<A>> tail;
Cons(final A head, final F0<Stream<A>> tail) {
this.head = head;
this.tail = weakMemo(tail);
}
public A head() {
return head;
}
public P1<Stream<A>> tail() {
return tail;
}
}
/**
* Returns a function that prepends (cons) an element to a stream to produce a new stream.
*
* @return A function that prepends (cons) an element to a stream to produce a new stream.
*/
public static <A> F<A, F<P1<Stream<A>>, Stream<A>>> cons() {
return a -> list -> cons(a, list);
}
/**
* Returns a function that prepends (cons) an element to a stream to produce a new stream.
*
* @return A function that prepends (cons) an element to a stream to produce a new stream.
*/
public static <A> F<A, F<Stream<A>, Stream<A>>> cons_() {
return curry((a, as) -> as.cons(a));
}
/**
* Returns an empty stream.
*
* @return An empty stream.
*/
public static <A> Stream<A> nil() {
return new Nil<>();
}
/**
* Returns an empty stream.
*
* @return An empty stream.
*/
public static <A> P1<Stream<A>> nil_() {
return P.lazy(Nil::new);
}
/**
* Returns a function that determines whether a given stream is empty.
*
* @return A function that determines whether a given stream is empty.
*/
public static <A> F<Stream<A>, Boolean> isEmpty_() {
return Stream::isEmpty;
}
/**
* Returns a function that determines whether a given stream is not empty.
*
* @return A function that determines whether a given stream is not empty.
*/
public static <A> F<Stream<A>, Boolean> isNotEmpty_() {
return Stream::isNotEmpty;
}
/**
* Returns a stream of one element containing the given value.
*
* @param a The value for the head of the returned stream.
* @return A stream of one element containing the given value.
*/
public static <A> Stream<A> single(final A a) {
return cons(a, Stream::nil);
}
/**
* Returns a function that yields a stream containing its argument.
*
* @return a function that yields a stream containing its argument.
*/
public static <A> F<A, Stream<A>> single() {
return Stream::single;
}
/**
* Prepends the given head element to the given tail element to produce a new stream.
*
* @param head The element to prepend.
* @param tail The stream to prepend to.
* @return The stream with the given element prepended.
*/
public static <A> Stream<A> cons(final A head, final F0<Stream<A>> tail) {
return new Cons<>(head, tail);
}
/**
* Joins the given stream of streams by concatenation.
*
* @param o The stream of streams to join.
* @return A new stream that is the join of the given streams.
*/
public static <A> Stream<A> join(final Stream<Stream<A>> o) { return o.bind(identity()); }
/**
* A first-class version of join
*
* @return A function that joins a stream of streams using a bind operation.
*/
public static <A> F<Stream<Stream<A>>, Stream<A>> join() {
return Stream::join;
}
/**
* Unfolds across the given function starting at the given value to produce a stream.
*
* @param f The function to unfold across.
* @param b The start value to begin the unfold.
* @return A new stream that is a result of unfolding until the function does not produce a
* value.
*/
public static <A, B> Stream<A> unfold(final F<B, Option<P2<A, B>>> f, final B b) {
final Option<P2<A, B>> o = f.f(b);
if (o.isNone())
return nil();
else {
final P2<A, B> p = o.some();
return cons(p._1(), () -> unfold(f, p._2()));
}
}
/**
* Creates a stream 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 stream 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> Stream<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);
}
/**
* Takes the given iterable to a stream.
*
* @param i The iterable to take to a stream.
* @return A stream from the given iterable.
*/
public static <A> Stream<A> iterableStream(final Iterable<A> i) {
return iteratorStream(i.iterator());
}
@SafeVarargs
public static <A> Stream<A> arrayStream(final A...as) {
return as.length == 0 ? Stream.nil()
: unfold(P2.tuple((as1, i) -> i >= as.length ? Option.none()
: some(p(as[i], p(as, i + 1)))), p(as, 0));
}
/**
* Returns an infinite-length stream of the given element.
*
* @param a The element to repeat infinitely.
* @return An infinite-length stream of the given element.
*/
public static <A> Stream<A> repeat(final A a) {
return cons(a, () -> repeat(a));
}
/**
* Returns an infinite-length stream of the given elements cycling. Fails on the empty stream.
*
* @param as The elements to cycle infinitely. This must not be empty.
* @return An infinite-length stream of the given elements cycling.
*/
public static <A> Stream<A> cycle(final Stream<A> as) {
if (as.isEmpty())
throw error("cycle on empty list");
else
return as.append(() -> cycle(as));
}
/**
* Returns a stream constructed by applying the given iteration function starting at the given value.
*
* @param f The iteration function.
* @param a The value to begin iterating from.
* @return A stream constructed by applying the given iteration function starting at the given value.
*/
public static <A> Stream<A> iterate(final F<A, A> f, final A a) {
return cons(a, () -> iterate(f, f.f(a)));
}
/**
* A first-class version of the iterate function.
*
* @return A function that returns a stream constructed by applying a given iteration function
* starting at a given value.
*/
public static <A> F<F<A, A>, F<A, Stream<A>>> iterate() {
return curry(Stream::iterate);
}
/**
* A first-class version of the bind function.
*
* @return A function that binds a given function across a given stream, joining the resulting streams.
*/
public static <A, B> F<F<A, Stream<B>>, F<Stream<A>, Stream<B>>> bind_() {
return curry((f, as) -> as.bind(f));
}
/**
* A first-class version of the foldRight function.
*
* @return A function that folds a given stream with a given function.
*/
public static <A, B> F<F<A, F<P1<B>, B>>, F<B, F<Stream<A>, B>>> foldRight() {
return curry((f, b, as) -> as.foldRight(f, b));
}
}