All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.tonivade.purefun.stream.PureStream Maven / Gradle / Ivy

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.Unit.unit;
import static com.github.tonivade.purefun.data.Sequence.asStream;

import java.util.Arrays;
import java.util.stream.Stream;

import com.github.tonivade.purefun.HigherKind;
import com.github.tonivade.purefun.Kind;

import com.github.tonivade.purefun.core.Bindable;
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.Operator1;
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.core.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.Instances;
import com.github.tonivade.purefun.typeclasses.MonadDefer;

@HigherKind
public sealed interface PureStream, T>
  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 matcher);
  PureStream takeWhile(Matcher1 matcher);
  PureStream dropWhile(Matcher1 matcher);

  default PureStream filterNot(Matcher1 matcher) {
    return filter(matcher.negate());
  }

   PureStream collect(PartialFunction1 partial);
   Kind foldLeft(R begin, Function2 combinator);
   Kind foldRight(Kind begin,
      Function2, ? extends Kind> combinator);

  @Override
   PureStream map(Function1 map);
  @Override
   PureStream flatMap(Function1, ? extends R>> map);
  @Override
  default  PureStream andThen(Kind, ? extends R> next) {
    return flatMap(ignore -> next);
  }

   PureStream mapEval(Function1> mapper);

  PureStream repeat();
  PureStream intersperse(Kind value);

  Kind exists(Matcher1 matcher);
  Kind forall(Matcher1 matcher);

  default , R> 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 > PureStream.Of of(MonadDefer monad) {
    return () -> monad;
  }

  static > PureStream.Of of(Class type) {
    return of(Instances.monadDefer(type));
  }

  @SafeVarargs
  static > PureStream.Of of(F...reified) {
    return of(Instances.monadDefer(reified));
  }

  @SafeVarargs
  static , T> PureStream empty(F... reified) {
    return of(Instances.monadDefer(reified)).empty();
  }

  @SafeVarargs
  static , T> PureStream pure(T value, F...reified) {
    return of(Instances.monadDefer(reified)).pure(value);
  }

  @SafeVarargs
  static , T> PureStream cons(T head, PureStream tail, F...reified) {
    return of(Instances.monadDefer(reified)).cons(head, tail);
  }

  @SafeVarargs
  static , T> PureStream suspend(Producer> lazy, F...reified) {
    return of(Instances.monadDefer(reified)).suspend(lazy);
  }

  @SafeVarargs
  static , T> PureStream eval(Kind value, F...reified) {
    return of(Instances.monadDefer(reified)).eval(value);
  }

  @SafeVarargs
  static , T> PureStream from(Iterable iterable, F...reified) {
    return of(Instances.monadDefer(reified)).from(iterable);
  }

  @SafeVarargs
  static , T> PureStream from(Stream stream, F...reified) {
    return of(Instances.monadDefer(reified)).from(stream);
  }

  @SafeVarargs
  static , T> PureStream from(Sequence sequence, F...reified) {
    return of(Instances.monadDefer(reified)).from(sequence);
  }

  @SafeVarargs
  static , T, S> PureStream unfold(
      S seed, Function1>> function, F...reified) {
    return of(Instances.monadDefer(reified)).unfold(seed, function);
  }

  @SafeVarargs
  static , T> PureStream iterate(T seed, Operator1 generator, F...reified) {
    return of(Instances.monadDefer(reified)).iterate(seed, generator);
  }

  @SafeVarargs
  static , T> PureStream iterate(Producer generator, F...reified) {
    return of(Instances.monadDefer(reified)).iterate(generator);
  }

  @SafeVarargs
  static , A, B, R> PureStream zipWith(PureStream s1, PureStream s2,
      Function2 combinator, F...reified) {
    return of(Instances.monadDefer(reified)).zipWith(s1, s2, combinator);
  }

  @SafeVarargs
  static , A, B> PureStream> zip(PureStream s1, PureStream s2, F...reified) {
    return of(Instances.monadDefer(reified)).zip(s1, s2);
  }

  @SafeVarargs
  static , A> PureStream> zipWithIndex(PureStream stream, F...reified) {
    return of(Instances.monadDefer(reified)).zipWithIndex(stream);
  }

  @SafeVarargs
  static , A> PureStream merge(PureStream s1, PureStream s2, F...reified) {
    return of(Instances.monadDefer(reified)).merge(s1, s2);
  }

  interface Of> {

    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> lazy) {
      return new Suspend<>(monadDefer(),
          monadDefer().defer(
              lazy.andThen(PureStreamOf::toPureStream).map(monadDefer()::>pure)));
    }

    default  PureStream eval(Kind value) {
      return new Cons<>(monadDefer(), Kind.narrowK(value), empty());
    }

    default  PureStream from(Iterable iterable) {
      return from(asStream(iterable.iterator()));
    }

    default  PureStream from(java.util.stream.Stream stream) {
      return from(ImmutableList.from(stream));
    }

    default  PureStream from(Sequence sequence) {
      return sequence.foldLeft(empty(), (acc, a) -> acc.append(monadDefer().pure(a)));
    }

    default  PureStream unfold(S seed, Function1>> 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 generator) {
      return unfold(unit(), unit -> Option.of(generator).map(next -> Tuple.of(next, unit)));
    }

    default  PureStream zipWith(PureStream s1, PureStream s2,
        Function2 combinator) {
      return new Suspend<>(monadDefer(), monadDefer().defer(
        () -> monadDefer().mapN(s1.split(), s2.split()).apply(
          (op1, op2) -> {
            Option> result = Option.map2(op1, op2,
              (t1, t2) -> {
                Kind head = monadDefer().mapN(t1.get1(), t2.get1()).apply(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()).apply(
          (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>> 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