
com.github.tonivade.purefun.stream.Cons Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of purefun-stream Show documentation
Show all versions of purefun-stream Show documentation
Functional Programming Library for Java
The newest version!
/*
* Copyright (c) 2018-2024, 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.core.Precondition.checkNonNull;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.core.Function1;
import com.github.tonivade.purefun.core.Function2;
import com.github.tonivade.purefun.core.Matcher1;
import com.github.tonivade.purefun.core.PartialFunction1;
import com.github.tonivade.purefun.core.Producer;
import com.github.tonivade.purefun.core.Tuple;
import com.github.tonivade.purefun.core.Tuple2;
import com.github.tonivade.purefun.type.Option;
import com.github.tonivade.purefun.typeclasses.MonadDefer;
public final class Cons, T> implements PureStream {
private final MonadDefer monad;
private final Kind head;
private final PureStream tail;
Cons(MonadDefer monad, Kind head, PureStream tail) {
this.monad = checkNonNull(monad);
this.head = checkNonNull(head);
this.tail = checkNonNull(tail);
}
@Override
public Kind> headOption() {
return monad.map(head, Option::some);
}
@Override
public Kind, PureStream>>> split() {
return monad.pure(Option.some(Tuple.of(head, tail)));
}
@Override
public PureStream concat(PureStream other) {
return suspend(() -> cons(head, tail.concat(other)));
}
@Override
public PureStream append(Kind other) {
return suspend(() -> cons(head, tail.append(other)));
}
@Override
public PureStream prepend(Kind other) {
return suspend(() -> cons(Kind.narrowK(other), tail.prepend(head)));
}
@Override
public PureStream take(int n) {
return n > 0 ? suspend(() -> cons(head, tail.take(n - 1))) : empty();
}
@Override
public PureStream drop(int n) {
return n > 0 ? suspend(() -> tail.drop(n - 1)) : this;
}
@Override
public PureStream takeWhile(Matcher1 super T> matcher) {
return suspendF(() -> monad.map(head,
t -> matcher.match(t) ? cons(head, tail.takeWhile(matcher)) : empty()));
}
@Override
public PureStream dropWhile(Matcher1 super T> matcher) {
return suspendF(() ->
monad.map(head, t -> matcher.match(t) ?
tail.dropWhile(matcher) : this));
}
@Override
public PureStream filter(Matcher1 super T> matcher) {
return suspendF(() ->
monad.map(head, t -> matcher.match(t) ?
cons(head, tail.filter(matcher)) : tail.filter(matcher)));
}
@Override
public PureStream collect(PartialFunction1 super T, ? extends R> partial) {
return suspendF(() ->
monad.map(head, t -> partial.isDefinedAt(t) ?
cons(monad.map(head, partial::apply), tail.collect(partial)) : tail.collect(partial)));
}
@Override
public Kind foldLeft(R begin, Function2 super R, ? super T, ? extends R> combinator) {
return monad.flatMap(head, h -> tail.foldLeft(combinator.apply(begin, h), combinator));
}
@Override
public Kind foldRight(Kind begin,
Function2 super T, ? super Kind, ? extends Kind> combinator) {
return monad.flatMap(head, h -> tail.foldRight(combinator.apply(h, begin), combinator));
}
@Override
public Kind exists(Matcher1 super T> matcher) {
return foldRight(monad.pure(false), (t, acc) -> matcher.match(t) ? monad.pure(true) : acc);
}
@Override
public Kind forall(Matcher1 super T> matcher) {
return foldRight(monad.pure(true), (t, acc) -> matcher.match(t) ? acc : monad.pure(false));
}
@Override
public PureStream map(Function1 super T, ? extends R> map) {
return suspend(() -> cons(monad.map(head, map), suspend(() -> tail.map(map))));
}
@Override
public PureStream mapEval(Function1 super T, ? extends Kind> mapper) {
return suspend(() -> cons(monad.flatMap(head, mapper), suspend(() -> tail.mapEval(mapper))));
}
@Override
public PureStream flatMap(Function1 super T, ? extends Kind, ? extends R>> map) {
return suspendF(() ->
monad.map(
monad.map(head, map.andThen(PureStreamOf::toPureStream)),
s -> s.concat(tail.flatMap(map))));
}
@Override
public PureStream repeat() {
return concat(suspend(this::repeat));
}
@Override
public PureStream intersperse(Kind value) {
return suspend(() -> cons(head, suspend(() -> cons(Kind.narrowK(value), tail.intersperse(value)))));
}
private PureStream cons(Kind h, PureStream t) {
return new Cons<>(monad, h, t);
}
private PureStream suspend(Producer> stream) {
return suspendF(stream.map(monad::>pure));
}
private PureStream suspendF(Producer>> stream) {
return new Suspend<>(monad, monad.defer(stream));
}
private PureStream empty() {
return new Nil<>(monad);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy