
com.github.tonivade.purefun.stream.Stream Maven / Gradle / Ivy
/*
* Copyright (c) 2018-2020, 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.Higher1;
import com.github.tonivade.purefun.HigherKind;
import com.github.tonivade.purefun.Kind;
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.Sealed;
import com.github.tonivade.purefun.Tuple;
import com.github.tonivade.purefun.Tuple2;
import com.github.tonivade.purefun.Unit;
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;
@Sealed
@HigherKind
public interface Stream {
default Stream head() {
return take(1);
}
default Stream tail() {
return drop(1);
}
Higher1> headOption();
Higher1, Stream>>> split();
Stream concat(Stream other);
Stream append(Higher1 other);
Stream prepend(Higher1 other);
Stream take(int n);
Stream drop(int n);
Stream filter(Matcher1 matcher);
Stream takeWhile(Matcher1 matcher);
Stream dropWhile(Matcher1 matcher);
default Stream filterNot(Matcher1 matcher) {
return filter(matcher.negate());
}
Stream collect(PartialFunction1 partial);
Higher1 foldLeft(R begin, Function2 combinator);
Higher1 foldRight(Higher1 begin, Function2, Higher1> combinator);
Stream map(Function1 map);
Stream flatMap(Function1> map);
Stream mapEval(Function1> mapper);
Stream repeat();
Stream intersperse(Higher1 value);
Higher1 exists(Matcher1 matcher);
Higher1 forall(Matcher1 matcher);
default Stream through(Function1, Stream> function) {
return function.apply(this);
}
default Higher1> asSequence() {
return foldLeft(ImmutableList.empty(), Sequence::append);
}
default Higher1 asString() {
return foldLeft("", (acc, a) -> acc + a);
}
default Higher1 drain() {
return foldLeft(unit(), (acc, a) -> acc);
}
default Stream andThen(Higher1 next) {
return mapEval(ignore -> next);
}
StreamModule getModule();
static StreamOf of(MonadDefer monad) {
return () -> monad;
}
interface StreamOf {
MonadDefer monadDefer();
default Stream empty() {
return new Nil<>(monadDefer());
}
@SuppressWarnings("unchecked")
default Stream of(T... values) {
return from(Arrays.stream(values));
}
default Stream pure(T value) {
return eval(monadDefer().pure(value));
}
default Stream cons(T head, Stream tail) {
return pure(head).concat(tail);
}
default Stream suspend(Producer> lazy) {
return new Suspend<>(monadDefer(), monadDefer().defer(lazy.map(monadDefer()::>pure)));
}
default Stream eval(Higher1 value) {
return new Cons<>(monadDefer(), value, empty());
}
default Stream from(Iterable iterable) {
return from(asStream(iterable.iterator()));
}
default Stream from(java.util.stream.Stream stream) {
return from(ImmutableList.from(stream));
}
default Stream from(Sequence sequence) {
return sequence.foldLeft(empty(), (acc, a) -> acc.append(monadDefer().pure(a)));
}
default Stream unfold(S seed, Function1>> function) {
return suspend(() -> StreamModule.unfold(this, seed, function));
}
default Stream iterate(T seed, Operator1 generator) {
return cons(seed, suspend(() -> iterate(generator.apply(seed), generator)));
}
default Stream iterate(Producer generator) {
return unfold(unit(), unit -> Option.of(generator).map(next -> Tuple.of(next, unit)));
}
default Stream zipWith(Stream s1, Stream s2, Function2 combinator) {
return new Suspend<>(monadDefer(), monadDefer().defer(
() -> monadDefer().map2(s1.split(), s2.split(),
(op1, op2) -> {
Option> result = StreamModule.map2(op1, op2,
(t1, t2) -> {
Higher1 head = monadDefer().map2(t1.get1(), t2.get1(), combinator);
Stream tail = zipWith(t1.get2(), t2.get2(), combinator);
return new Cons<>(monadDefer(), head, tail);
});
return result.getOrElse(this::empty);
})
));
}
default Stream> zip(Stream s1, Stream s2) {
return zipWith(s1, s2, Tuple2::of);
}
default Stream> zipWithIndex(Stream stream) {
return zip(stream, iterate(0, x -> x + 1));
}
default Stream merge(Stream s1, Stream s2) {
return new Suspend<>(monadDefer(), monadDefer().defer(
() -> monadDefer().map2(s1.split(), s2.split(),
(opt1, opt2) -> {
Option> result = StreamModule.map2(opt1, opt2,
(t1, t2) -> {
Higher1 head = t1.get1();
Stream tail = eval(t2.get1()).concat(merge(t1.get2(), t2.get2()));
return new Cons<>(monadDefer(), head, tail);
});
return result.getOrElse(this::empty);
})
));
}
}
}
interface StreamModule {
static Option map2(Option fa, Option fb, Function2 combiner) {
return fa.flatMap(a -> fb.map(b -> combiner.apply(a, b)));
}
static Stream unfold(Stream.StreamOf streamOf, S seed,
Function1>> function) {
return function.apply(seed)
.map(tuple -> streamOf.cons(tuple.get1(), streamOf.suspend(() -> unfold(streamOf, tuple.get2(), function))))
.getOrElse(streamOf::empty);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy