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

com.github.tonivade.purefun.stream.Cons 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.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 matcher) {
    return suspendF(() -> monad.map(head,
        t -> matcher.match(t) ? cons(head, tail.takeWhile(matcher)) : empty()));
  }

  @Override
  public PureStream dropWhile(Matcher1 matcher) {
    return suspendF(() ->
            monad.map(head, t -> matcher.match(t) ?
                tail.dropWhile(matcher) : this));
  }

  @Override
  public PureStream filter(Matcher1 matcher) {
    return suspendF(() ->
            monad.map(head, t -> matcher.match(t) ?
                cons(head, tail.filter(matcher)) : tail.filter(matcher)));
  }

  @Override
  public  PureStream collect(PartialFunction1 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 combinator) {
    return monad.flatMap(head, h -> tail.foldLeft(combinator.apply(begin, h), combinator));
  }

  @Override
  public  Kind foldRight(Kind begin,
      Function2, ? extends Kind> combinator) {
    return monad.flatMap(head, h -> tail.foldRight(combinator.apply(h, begin), combinator));
  }

  @Override
  public Kind exists(Matcher1 matcher) {
    return foldRight(monad.pure(false), (t, acc) -> matcher.match(t) ? monad.pure(true) : acc);
  }

  @Override
  public Kind forall(Matcher1 matcher) {
    return foldRight(monad.pure(true), (t, acc) -> matcher.match(t) ? acc : monad.pure(false));
  }

  @Override
  public  PureStream map(Function1 map) {
    return suspend(() -> cons(monad.map(head, map), suspend(() -> tail.map(map))));
  }

  @Override
  public  PureStream mapEval(Function1> mapper) {
    return suspend(() -> cons(monad.flatMap(head, mapper), suspend(() -> tail.mapEval(mapper))));
  }

  @Override
  public  PureStream flatMap(Function1, ? 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