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

com.github.tonivade.purefun.instances.SequenceInstances 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.instances;

import com.github.tonivade.purefun.Eq;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.Function2;
import com.github.tonivade.purefun.Kind;
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.data.SequenceOf;
import com.github.tonivade.purefun.data.Sequence_;
import com.github.tonivade.purefun.type.Eval;
import com.github.tonivade.purefun.typeclasses.Alternative;
import com.github.tonivade.purefun.typeclasses.Applicative;
import com.github.tonivade.purefun.typeclasses.Foldable;
import com.github.tonivade.purefun.typeclasses.Functor;
import com.github.tonivade.purefun.typeclasses.Monad;
import com.github.tonivade.purefun.typeclasses.Monoid;
import com.github.tonivade.purefun.typeclasses.MonoidK;
import com.github.tonivade.purefun.typeclasses.Semigroup;
import com.github.tonivade.purefun.typeclasses.SemigroupK;
import com.github.tonivade.purefun.typeclasses.Traverse;

@SuppressWarnings("unchecked")
public interface SequenceInstances {

  static  Eq> eq(Eq eqElement) {
    return (a, b) -> {
      Sequence seq1 = SequenceOf.narrowK(a);
      Sequence seq2 = SequenceOf.narrowK(b);
      return seq1.size() == seq2.size()
          && Sequence.zip(seq1, seq2).allMatch(tuple -> eqElement.eqv(tuple.get1(), tuple.get2()));
    };
  }

  static  Semigroup> semigroup() {
    return (SequenceSemigroup) SequenceSemigroup.INSTANCE;
  }

  static  Monoid> monoid() {
    return (SequenceMonoid) SequenceMonoid.INSTANCE;
  }

  static SemigroupK semigroupK() {
    return SequenceSemigroupK.INSTANCE;
  }

  static MonoidK monoidK() {
    return SequenceMonoidK.INSTANCE;
  }

  static Functor functor() {
    return SequenceFunctor.INSTANCE;
  }

  static Applicative applicative() {
    return SequenceApplicative.INSTANCE;
  }

  static SequenceMonad monad() {
    return SequenceMonad.INSTANCE;
  }

  static Alternative alternative() {
    return SequenceAlternative.INSTANCE;
  }

  static Traverse traverse() {
    return SequenceTraverse.INSTANCE;
  }

  static Foldable foldable() {
    return SequenceFoldable.INSTANCE;
  }
}

interface SequenceSemigroup extends Semigroup> {

  SequenceSemigroup INSTANCE = new SequenceSemigroup() {};

  @Override
  default Sequence combine(Sequence t1, Sequence t2) {
    return t1.appendAll(t2);
  }
}

interface SequenceMonoid extends SequenceSemigroup, Monoid> {

  SequenceMonoid INSTANCE = new SequenceMonoid() {};

  @Override
  default Sequence zero() {
    return ImmutableList.empty();
  }
}

interface SequenceSemigroupK extends SemigroupK {

  SequenceSemigroupK INSTANCE = new SequenceSemigroupK() {};

  @Override
  default  Kind combineK(Kind t1, Kind t2) {
    return SequenceOf.narrowK(t1).appendAll(SequenceOf.narrowK(t2));
  }
}

interface SequenceMonoidK extends MonoidK, SequenceSemigroupK {

  SequenceMonoidK INSTANCE = new SequenceMonoidK() {};

  @Override
  default  Kind zero() {
    return ImmutableList.empty();
  }
}

interface SequenceFunctor extends Functor {

  SequenceFunctor INSTANCE = new SequenceFunctor() {};

  @Override
  default  Kind map(Kind value, Function1 map) {
    return SequenceOf.narrowK(value).map(map);
  }
}

interface SequencePure extends Applicative {

  @Override
  default  Kind pure(T value) {
    return ImmutableList.of(value);
  }
}

interface SequenceApplicative extends SequencePure, Applicative {

  SequenceApplicative INSTANCE = new SequenceApplicative() {};

  @Override
  default  Kind ap(Kind value, Kind> apply) {
    return SequenceOf.narrowK(apply).flatMap(map -> SequenceOf.narrowK(value).map(map));
  }
}

interface SequenceMonad extends SequencePure, Monad {

  SequenceMonad INSTANCE = new SequenceMonad() {};

  @Override
  default  Kind flatMap(Kind value, Function1> map) {
    return SequenceOf.narrowK(value).flatMap(map.andThen(SequenceOf::narrowK));
  }
}

interface SequenceAlternative
    extends SequenceApplicative, SequenceMonoidK, Alternative {

  SequenceAlternative INSTANCE = new SequenceAlternative() {};
}


interface SequenceFoldable extends Foldable {

  SequenceFoldable INSTANCE = new SequenceFoldable() {};

  @Override
  default  B foldLeft(Kind value, B initial, Function2 mapper) {
    return SequenceOf.narrowK(value).foldLeft(initial, mapper);
  }

  @Override
  default  Eval foldRight(Kind value, Eval initial, Function2, Eval> mapper) {
    return SequenceOf.narrowK(value).foldRight(initial, mapper);
  }
}

interface SequenceTraverse extends Traverse, SequenceFoldable {

  SequenceTraverse INSTANCE = new SequenceTraverse() {};

  @Override
  default  Kind> traverse(
      Applicative applicative, Kind value,
      Function1> mapper) {
    return SequenceOf.narrowK(value).foldRight(
      applicative.pure(ImmutableList.empty()),
      (a, acc) -> applicative.map2(mapper.apply(a), acc,
        (e, seq) -> Sequence.listOf(e).appendAll(SequenceOf.narrowK(seq))));
  }
}