cyclops.hkt.Nested Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cyclops-pure Show documentation
Show all versions of cyclops-pure Show documentation
Platform for Functional Reactive Programming with Java 8
package cyclops.hkt;
import com.oath.cyclops.hkt.DataWitness;
import com.oath.cyclops.hkt.DataWitness.completableFuture;
import com.oath.cyclops.hkt.DataWitness.either;
import com.oath.cyclops.hkt.DataWitness.future;
import com.oath.cyclops.hkt.DataWitness.nested;
import com.oath.cyclops.hkt.DataWitness.optional;
import com.oath.cyclops.hkt.DataWitness.seq;
import com.oath.cyclops.hkt.DataWitness.stream;
import com.oath.cyclops.hkt.DataWitness.tryType;
import com.oath.cyclops.hkt.DataWitness.vector;
import com.oath.cyclops.hkt.Higher;
import com.oath.cyclops.hkt.Higher3;
import com.oath.cyclops.types.foldable.To;
import com.oath.cyclops.types.functor.Transformable;
import cyclops.arrow.Cokleisli;
import cyclops.arrow.Kleisli;
import cyclops.arrow.MonoidK;
import cyclops.arrow.SemigroupK;
import cyclops.companion.Monoids;
import cyclops.control.Either;
import cyclops.control.Future;
import cyclops.control.Maybe;
import cyclops.control.Option;
import cyclops.control.Try;
import cyclops.data.ImmutableList;
import cyclops.data.LazySeq;
import cyclops.data.Seq;
import cyclops.data.Vector;
import cyclops.data.tuple.Tuple;
import cyclops.data.tuple.Tuple2;
import cyclops.function.Function3;
import cyclops.function.Function4;
import cyclops.function.Group;
import cyclops.function.Monoid;
import cyclops.instances.control.EitherInstances;
import cyclops.instances.control.FutureInstances;
import cyclops.instances.control.TryInstances;
import cyclops.instances.data.SeqInstances;
import cyclops.instances.data.VectorInstances;
import cyclops.instances.jdk.CompletableFutureInstances;
import cyclops.instances.jdk.OptionalInstances;
import cyclops.instances.jdk.StreamInstances;
import cyclops.kinds.CompletableFutureKind;
import cyclops.kinds.OptionalKind;
import cyclops.kinds.StreamKind;
import cyclops.reactive.ReactiveSeq;
import cyclops.transformers.Transformer;
import cyclops.transformers.TransformerFactory;
import cyclops.typeclasses.Comprehensions;
import cyclops.typeclasses.InstanceDefinitions;
import cyclops.typeclasses.Pure;
import cyclops.typeclasses.comonad.Comonad;
import cyclops.typeclasses.foldable.Foldable;
import cyclops.typeclasses.foldable.Unfoldable;
import cyclops.typeclasses.functor.Compose;
import cyclops.typeclasses.functor.Functor;
import cyclops.typeclasses.monad.Applicative;
import cyclops.typeclasses.monad.ComposedTraverse;
import cyclops.typeclasses.monad.Monad;
import cyclops.typeclasses.monad.MonadPlus;
import cyclops.typeclasses.monad.MonadRec;
import cyclops.typeclasses.monad.MonadZero;
import cyclops.typeclasses.monad.Traverse;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
/**
* Class for working with Nested Data Structures.
*
* E.g. to work with a List of Optionals
*
* {@code
* import Witness.list;
import Witness.optional;
* Nested listOfOptionalInt = Nested.of(ListX.of(Optionals.OptionalKind.of(2)),ListX.Instances.definitions(),Optionals.Instances.definitions());
* //Nested[List[Optional[2]]]
* }
*
*
*
* Transform nest data
*
* {@code
* Nested listOfOptionalInt; //Nested[List[Optional[2]]]
* Nested doubled = listOfOptionalInt.map(i->i*2);
* //Nested[List[Optional[4]]]
* }
*
*
*
*
* Sequencing data
*
* {@code
* Nested listOfOptionalInt; //Nested[List[Optional[2]]]
* Nested sequenced = listOfOptionalInt.sequence();
* //Nested[Optional[List[2]]]
*
* }
*
*
*
*
*
* @param First Witness type {@see Witness}
* @param Second Witness type {@see Witness}
* @param Nested Data Type
*/
@AllArgsConstructor(access= AccessLevel.PRIVATE)
@EqualsAndHashCode(of={"nested"})
public class Nested implements Transformable,
Higher3,To> {
public final Higher> nested;
private final Compose composedFunctor;
public final InstanceDefinitions def1;
public final InstanceDefinitions def2;
public Transformer transformer(TransformerFactory factory){
return factory.build(this);
}
public static Nested of(Higher> nested,InstanceDefinitions def1,InstanceDefinitions def2){
Compose composed = Compose.compose(def1.functor(),def2.functor());
return new Nested<>(narrow(nested),composed,def1,def2);
}
public static Nested of(Active> nested,InstanceDefinitions def2){
Compose composed = Compose.compose(nested.getDef1().functor(),def2.functor());
return new Nested<>(narrow(nested.getActive()),composed,nested.getDef1(),def2);
}
public static Higher> narrow(Higher> nested){
return (Higher>) nested;
}
public static Active flatten(Nested nested){
return Active.of(nested.def1.monad().flatMap(i->i,nested.nested),nested.def1);
}
public Higher> getNested() {
return nested;
}
public R fold(Function super Higher>, ? extends R> fn){
return fn.apply(nested);
}
public Active pure1(R value){
return Active.of(def1.unit().unit(value),def1);
}
public Nested pure2(R value){
return Nested.of(def1.unit().unit(def2.unit().unit(value)),def1,def2);
}
public Nested map(Function super T,? extends R> fn){
Higher> res = composedFunctor.map(fn, nested);
return new Nested<>(res,composedFunctor,def1,def2);
}
public Active> toSeq(){
return Active.of(def1.functor().map(i->def2.foldable().seq(i),nested),def1);
}
public Active> toLazySeq(){
return Active.of(def1.functor().map(i->def2.foldable().lazySeq(i),nested),def1);
}
public Seq toSeqBoth(){
return toSeq().foldLeft(Monoids.seqConcat());
}
public LazySeq toLazySeqBoth(){
return toLazySeq().foldLeft(Monoids.lazySeqConcat());
}
public Active> stream(){
return toLazySeq().map(i->i.stream());
}
public ReactiveSeq streamBoth(){
return stream().foldLeft(Monoids.combineReactiveSeq());
}
public Active size() {
return Active.of(def1.functor().map(i->def2.foldable().size(i),nested),def1);
}
public Nested reverse(){
return Nested.of(def1.traverse().reverse( def1.functor().map(i->def2.traverse().reverse(i),nested)),def1,def2);
}
public long totalSize() {
return size().foldLeft(Monoids.longSum);
}
public Nested peek(Consumer super T> fn){
Higher> res = composedFunctor.peek(fn, nested);
return new Nested<>(res,composedFunctor,def1,def2);
}
public Function, Nested> lift(final Function super T, ? extends R> fn) {
return t -> map(fn);
}
public Nested ap(Higher> fn){
Higher> res = def1.functor().map(a -> def2.applicative().ap(fn, a), nested);
return of(res,def1,def2);
}
public Nested flatMap(Function super T, ? extends Higher> fn){
Higher> res = composedFunctor.map1(a->def2.monad().flatMap(fn, a),nested);
return new Nested<>(res,composedFunctor,def1,def2);
}
public Nested flatMap(Function super X,? extends Higher> widenFn,Function super T,? extends X> fn){
Higher> res = composedFunctor.map1(a->def2.monad().flatMap(fn.andThen(widenFn), a),nested);
return new Nested<>(res,composedFunctor,def1,def2);
}
public Nested zip(Higher fb, BiFunction super T,? super T2,? extends R> f) {
return of(def1.functor().map_(nested, i -> def2.applicative().zip(i, fb, f)),def1,def2);
}
public Nested> zip(Higher fb) {
return zip(fb,Tuple::tuple);
}
public Narrowed concreteMonoid(Kleisli widen, Cokleisli narrow){
return new Narrowed(widen,narrow);
}
public NarrowedFlatMap concreteFlatMap(Kleisli widen){
return new NarrowedFlatMap<>(widen);
}
public NarrowedApplicative concreteAp(Kleisli> widen){
return new NarrowedApplicative<>(widen);
}
public NarrowedTailRec concreteTailRec(Kleisli> widen){
return new NarrowedTailRec<>(widen);
}
public Converter concreteConversion(Function super Higher,? extends S> narrow2){
return new Converter(){
@Override
public Active to(Function fn) {
return Active.of(def1.functor().map(f -> fn.apply(narrow2.apply(f)), nested),def1);
}
};
}
public static interface Converter{
public Active to(Function fn);
}
@AllArgsConstructor
class NarrowedFlatMap{
private final Kleisli widen;
public Nested flatMap(Function super T, ? extends C> fn) {
return Nested.this.flatMap(fn.andThen(widen));
}
public Nested zip(C fb, BiFunction super T,? super R,? extends R2> f) {
return Nested.this.zip(widen.apply(fb),f);
}
public Nested> zip(C fb) {
return Nested.this.zip(widen.apply(fb));
}
}
@AllArgsConstructor
class NarrowedTailRec{
private final Kleisli> widen;
public Nested tailRecN(T initial,Function super T,? extends C> fn){
return Nested.this.tailRecN(initial,fn.andThen(widen));
}
}
@AllArgsConstructor
class NarrowedApplicative{
private final Kleisli> widen;
public Nested ap(C fn) {
return Nested.this.ap(widen.apply(fn));
}
}
@AllArgsConstructor
class Narrowed{
//plus, sum
private final Kleisli widen;
private final Cokleisli narrow;
public Active extract(){
return Active.of(def1.functor().map_(nested,f->narrow.apply(f)),def1);
}
public Nested plus(Monoid m,C add){
return sum(m,LazySeq.of(add));
}
public Nested sum(C seed, BinaryOperator op,ImmutableList list){
return of(def1.functor().map_(nested,f-> {
C res = list.plus(narrow.apply(f)).foldLeft(seed, (a, b) -> op.apply(a, b));
return widen.apply(res);
}),def1,def2);
}
public Nested sum(Monoid s,ImmutableList list){
return of(def1.functor().map_(nested,f-> {
C res = list.plus(narrow.apply(f)).foldLeft(s.zero(), (a, b) -> s.apply(a, b));
return widen.apply(res);
}),def1,def2);
}
public Nested sumInverted(Group s, ImmutableList list){
return of(def1.functor().map_(nested,f-> {
C res = s.invert(list.plus(narrow.apply(f)).foldLeft(s.zero(),(a,b)->s.apply(a,b)));
return widen.apply(res);
}),def1,def2);
}
public Maybe> sum(ImmutableList list){
return Nested.this.plus().flatMap(s ->
Maybe.just(sum(narrow.apply(s.monoid().zero()), (C a, C b) -> narrow.apply(s.monoid().apply(widen.apply(a), widen.apply(b))), list))
);
}
}
public Nested flatMapA(Function super T, ? extends Active> fn){
Higher> res = composedFunctor.map1(a->def2.monad().flatMap(fn.andThen(t->t.getSingle()), a),nested);
return new Nested<>(res,composedFunctor,def1,def2);
}
public Nested tailRecN(T initial,Function super T,? extends Higher>> fn){
return flatMapA(in->Active.of(def2.unit().unit(in),def2).tailRec(initial,fn));
}
public Nested tailRec(T initial,Function super T,? extends Nested>> fn){
return narrowK(Instances.monadRec(def1, def2).tailRec(initial, fn));
}
public Unfolds unfolds(Unfoldable unf){
return new Unfolds(unf);
}
public Plus plus(MonadPlus plus1, MonadPlus plus2){
return new Plus(plus1,plus2);
}
public Unfolds unfoldsUnsafe(){
return def2.unfoldable().fold(s-> new Unfolds(s),()->new Unfolds(new Unfoldable.UnsafeValueUnfoldable<>()));
}
private Plus plusUnsafe(){
return new Plus(def1.monadPlus().orElse(null),def2.monadPlus().orElse(null));
}
public Maybe unfolds(){
return def2.unfoldable().fold(s-> Maybe.just(new Unfolds(s)),Maybe::nothing);
}
public Nested plusNested(SemigroupK semigroupK, Higher add){
return of(def1.functor().map(i -> semigroupK.apply(i, add),nested), def1, def2);
}
public Maybe plus(){
if(def1.monadPlus().isPresent() && def2.monadPlus().isPresent()){
return Maybe.just(plusUnsafe());
}
return Maybe.nothing();
}
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Plus{
private final MonadPlus plus1;
private final MonadPlus plus2;
public Monoid> monoid(){
return def2.monadPlus().orElse(null).monoid().asMonoid();
}
public Nested sum(ImmutableList> list){
return of(plus1.sum(list.plus(Nested.this).map(x -> x.nested)),def1,def2);
}
public Nested plus(Higher b){
Functor f = def1.functor();
MonadPlus mp = plus2;
Higher> x = f.map(a -> mp.plus(a, b), nested);
return of(x,def1,def2);
}
public Nested plus(Nested b){
Monad f = def1.monad();
MonadPlus mp = plus2;
Higher> x2 = f.flatMap(a -> {
Nested r = plus(a);
return r.nested;
}, b.nested);
return of(x2,def1,def2);
}
}
public R foldMapBoth(final Monoid mb, final Function super T,? extends R> fn) {
return def1.foldable().foldRight(mb,foldMap(mb,fn));
}
public T foldBothl(T identity, BinaryOperator semigroup){
return def1.foldable().foldLeft(identity,semigroup,foldLeft(Monoid.fromBiFunction(identity, semigroup)));
}
public T foldBothr(T identity, BinaryOperator semigroup){
return def1.foldable().foldRight(identity,semigroup,foldRight(Monoid.fromBiFunction(identity, semigroup)));
}
public T foldBothRight(Monoid monoid){
return def1.foldable().foldRight(monoid,foldRight(monoid));
}
public T foldBothLeft(Monoid monoid){
return def1.foldable().foldLeft(monoid,foldLeft(monoid));
}
public R foldRight(Monoid monoid, Function super Higher,? extends R> narrowK){
return narrowK.apply(foldRight(monoid));
}
public R foldLeft(Monoid monoid, Function super Higher,? extends R> narrowK){
return narrowK.apply(foldLeft(monoid));
}
public Active foldl(T identity, BinaryOperator semigroup){
return foldl(Monoid.fromBiFunction(identity, semigroup));
}
public Active foldr(T identity, BinaryOperator semigroup){
return foldr(Monoid.fromBiFunction(identity, semigroup));
}
public Active foldl(Monoid monoid){
return Active.of(foldLeft(monoid),def1);
}
public Active foldr(Monoid monoid){
return Active.of(foldRight(monoid),def1);
}
public Active foldMapA(final Monoid mb, final Function super T,? extends R> fn) {
return Active.of(foldMap(mb, fn), def1);
}
public Higher foldMap(final Monoid mb, final Function super T,? extends R> fn) {
return def1.functor().map(a -> def2.foldable().foldMap(mb, fn,a), nested);
}
public Higher foldRight(Monoid monoid){
return def1.functor().map(a -> def2.foldable().foldRight(monoid, a), nested);
}
public Higher foldLeft(Monoid monoid){
return def1.functor().map(a -> def2.foldable().foldLeft(monoid, a), nested);
}
public Higher foldLeft(T identity, BinaryOperator semigroup){
return foldLeft(Monoid.fromBiFunction(identity, semigroup));
}
public Higher foldRight(T identity, BinaryOperator semigroup){
return foldRight(Monoid.fromBiFunction(identity, semigroup));
}
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Unfolds{
private final Unfoldable unfold2;
public Nested unfold(Function super T, Option>> fn){
Unfoldable unf = unfold2;
Higher> x = def1.functor().map(a -> def2.monad().flatMap(c -> unf.unfold(c, fn), a), nested);
return Nested.of(x,def1,def2);
}
private Nested unfoldPrivate(T2 b,Function>> fn){
Unfoldable unf = unfold2;
Higher> x = def1.functor().map(a -> def2.monad().flatMap(c -> unf.unfold(b, fn.andThen(o->o.map(t->t.map1(v->c)))), a), nested);
return Nested.of(x,def1,def2);
}
private Nested unfoldIgnore(T b,Function>> fn){
Unfoldable unf = unfold2;
Higher> x = def1.functor().map(a -> def2.monad().flatMap(c -> unf.unfold(b, fn), a), nested);
return Nested.of(x,def1,def2);
}
public Nested replaceWith(int n, R value) {
return this.unfoldIgnore(n, i-> Option.of(Tuple.tuple(value, i - 1)));
}
public Nested replicate(int n) {
return this.unfoldPrivate(n, i-> Option.some(Tuple.tuple(null, i - 1)));
}
public Nested none() {
return unfold(t -> Option.>none());
}
public Nested replaceWith(R a) {
return replaceWith(1, a);
}
}
public Higher> traverseA(Applicative applicative, Function super T, ? extends Higher> fn){
Nested n = this;
ComposedTraverse ct = ComposedTraverse.of(n.def1.traverse(),n.def2.traverse(),n.def2.applicative());
Higher>> r = ct.traverse(applicative,fn,n.nested);
Higher> x = applicative.map(nr -> Nested.of(nr, n.def1, n.def2), r);
return x;
}
public Higher> sequenceA(Applicative applicative,
Nested> ds){
Higher, W2>, T>> x = Instances.traverseA(applicative, a -> a, ds);
return (Higher)x;
}
public Higher> flatTraverse(Applicative applicative,
Function super T,? extends Higher>> f, TransformerFactory factory) {
return applicative.map_(traverseA(applicative, f), it-> it.transformer(factory).flatMap(a->a));
}
public Higher> flatSequence(Applicative applicative, Nested>> fgfa,TransformerFactory factory) {
return applicative.map(i -> i.transformer(factory).flatMap(Function.identity()),sequenceA(applicative, fgfa) );
}
public Nested sequence(){
Higher> res = def1.traverse().sequenceA(def2.applicative(), nested);
return of(res,def2,def1);
}
public Nested traverse(Function super T,? extends R> fn){
return sequence().map(fn);
}
public String toString(){
return "Nested["+nested.toString()+"]";
}
public static Nested completableFutureStream(CompletableFuture extends Stream> optionalList){
CompletableFutureKind> opt = CompletableFutureKind.widen(optionalList.thenApply(StreamKind::widen));
Higher