
com.github.tonivade.purefun.stream.PureStream Maven / Gradle / Ivy
/*
* Copyright (c) 2018-2023, Antonio Gabriel Muñoz Conejo
* Distributed under the terms of the MIT License
*/
package com.github.tonivade.purefun.stream;
import static com.github.tonivade.purefun.Unit.unit;
import static com.github.tonivade.purefun.data.Sequence.asStream;
import java.util.Arrays;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.Function2;
import com.github.tonivade.purefun.HigherKind;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.Bindable;
import com.github.tonivade.purefun.Matcher1;
import com.github.tonivade.purefun.Operator1;
import com.github.tonivade.purefun.PartialFunction1;
import com.github.tonivade.purefun.Producer;
import com.github.tonivade.purefun.Tuple;
import com.github.tonivade.purefun.Tuple2;
import com.github.tonivade.purefun.Unit;
import com.github.tonivade.purefun.Witness;
import com.github.tonivade.purefun.data.ImmutableList;
import com.github.tonivade.purefun.data.Sequence;
import com.github.tonivade.purefun.type.Option;
import com.github.tonivade.purefun.typeclasses.MonadDefer;
@HigherKind
public sealed interface PureStream extends PureStreamOf, Bindable, T> permits Cons, Suspend, Nil {
default PureStream head() {
return take(1);
}
default PureStream tail() {
return drop(1);
}
Kind> headOption();
Kind, PureStream>>> split();
PureStream concat(PureStream other);
PureStream append(Kind other);
PureStream prepend(Kind other);
PureStream take(int n);
PureStream drop(int n);
PureStream filter(Matcher1 super T> matcher);
PureStream takeWhile(Matcher1 super T> matcher);
PureStream dropWhile(Matcher1 super T> matcher);
default PureStream filterNot(Matcher1 super T> matcher) {
return filter(matcher.negate());
}
PureStream collect(PartialFunction1 super T, ? extends R> partial);
Kind foldLeft(R begin, Function2 super R, ? super T, ? extends R> combinator);
Kind foldRight(Kind begin,
Function2 super T, ? super Kind, ? extends Kind> combinator);
@Override
PureStream map(Function1 super T, ? extends R> map);
@Override
PureStream flatMap(Function1 super T, ? extends Kind, ? extends R>> map);
@Override
default PureStream andThen(Kind, ? extends R> next) {
return flatMap(ignore -> next);
}
PureStream mapEval(Function1 super T, ? extends Kind> mapper);
PureStream repeat();
PureStream intersperse(Kind value);
Kind exists(Matcher1 super T> matcher);
Kind forall(Matcher1 super T> matcher);
default PureStream through(Function1, PureStream> function) {
return function.apply(this);
}
default Kind> asSequence() {
return foldLeft(ImmutableList.empty(), Sequence::append);
}
default Kind asString() {
return foldLeft("", (acc, a) -> acc + a);
}
default Kind drain() {
return foldLeft(unit(), (acc, a) -> acc);
}
default PureStream mapReplace(Kind next) {
return mapEval(ignore -> next);
}
static StreamOf of(MonadDefer monad) {
return () -> monad;
}
interface StreamOf {
MonadDefer monadDefer();
default PureStream empty() {
return new Nil<>(monadDefer());
}
@SuppressWarnings("unchecked")
default PureStream of(T... values) {
return from(Arrays.stream(values));
}
default PureStream pure(T value) {
return eval(monadDefer().pure(value));
}
default PureStream cons(T head, PureStream tail) {
return pure(head).concat(tail);
}
default PureStream suspend(Producer extends PureStream> lazy) {
return new Suspend<>(monadDefer(),
monadDefer().defer(
lazy.andThen(PureStreamOf::narrowK).map(monadDefer()::>pure)));
}
default PureStream eval(Kind value) {
return new Cons<>(monadDefer(), Kind.narrowK(value), empty());
}
default PureStream from(Iterable extends T> iterable) {
return from(asStream(iterable.iterator()));
}
default PureStream from(java.util.stream.Stream extends T> stream) {
return from(ImmutableList.from(stream));
}
default PureStream from(Sequence extends T> sequence) {
return sequence.foldLeft(empty(), (acc, a) -> acc.append(monadDefer().pure(a)));
}
default PureStream unfold(S seed, Function1 super S, Option>> function) {
return suspend(() -> doUnfold(seed, function));
}
default PureStream iterate(T seed, Operator1 generator) {
return cons(seed, suspend(() -> iterate(generator.apply(seed), generator)));
}
default PureStream iterate(Producer extends T> generator) {
return unfold(unit(), unit -> Option.of(generator).map(next -> Tuple.of(next, unit)));
}
default PureStream zipWith(PureStream s1, PureStream s2,
Function2 super A, ? super B, ? extends R> combinator) {
return new Suspend<>(monadDefer(), monadDefer().defer(
() -> monadDefer().mapN(s1.split(), s2.split(),
(op1, op2) -> {
Option> result = Option.map2(op1, op2,
(t1, t2) -> {
Kind head = monadDefer().mapN(t1.get1(), t2.get1(), combinator);
PureStream tail = zipWith(t1.get2(), t2.get2(), combinator);
return new Cons<>(monadDefer(), head, tail);
});
return result.getOrElse(this::empty);
})
));
}
default PureStream> zip(PureStream s1, PureStream s2) {
return zipWith(s1, s2, Tuple2::of);
}
default PureStream> zipWithIndex(PureStream stream) {
return zip(stream, iterate(0, x -> x + 1));
}
// TODO: generics
default PureStream merge(PureStream s1, PureStream s2) {
return new Suspend<>(monadDefer(), monadDefer().defer(
() -> monadDefer().mapN(s1.split(), s2.split(),
(opt1, opt2) -> {
Option> result = Option.map2(opt1, opt2,
(t1, t2) -> {
Kind head = t1.get1();
PureStream tail = eval(t2.get1()).concat(merge(t1.get2(), t2.get2()));
return new Cons<>(monadDefer(), head, tail);
});
return result.getOrElse(this::empty);
})
));
}
private PureStream doUnfold(S seed, Function1 super S, Option>> function) {
return function.apply(seed)
.map(tuple -> tuple.applyTo((t, s) -> cons(t, suspend(() -> doUnfold(s, function)))))
.getOrElse(this::empty);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy