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

cyclops.hkt.Product Maven / Gradle / Ivy

The newest version!
package cyclops.hkt;


import com.oath.cyclops.hkt.Higher;
import com.oath.cyclops.hkt.Higher3;
import com.oath.cyclops.types.Filters;
import com.oath.cyclops.types.foldable.To;
import com.oath.cyclops.types.functor.Transformable;
import cyclops.control.*;
import cyclops.control.Maybe;
import cyclops.data.ImmutableList;
import cyclops.data.LazySeq;
import cyclops.data.Seq;
import cyclops.function.Function3;
import cyclops.function.Function4;
import cyclops.function.Monoid;
import com.oath.cyclops.hkt.DataWitness.*;
import cyclops.reactive.ReactiveSeq;
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.arrow.MonoidK;
import cyclops.arrow.SemigroupK;
import cyclops.typeclasses.functor.Functor;
import cyclops.typeclasses.monad.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import cyclops.data.tuple.Tuple;
import cyclops.data.tuple.Tuple2;
import cyclops.data.tuple.Tuple3;

import java.util.Arrays;
import java.util.function.*;

import static cyclops.data.tuple.Tuple.tuple;

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@EqualsAndHashCode(of="run")
@Getter
public class Product implements  Filters,
                                            Higher3,
                                            Transformable,
                                            To> {

    private final Tuple2,Higher> run;
    private final InstanceDefinitions def1;
    private final InstanceDefinitions def2;


    public Tuple2,Higher> asTuple(){
        return run;
    }
    public Tuple2,Active> asActiveTuple(){
        return run.transform((a, b)->Tuple.tuple(Active.of(a,def1),Active.of(b,def2)));
    }

    public Active _1(){
        return Active.of(run._1(),def1);
    }
    public Active _2(){
        return Active.of(run._2(),def2);
    }

    public static   Product of(Tuple2,
            Higher> run, InstanceDefinitions def1, InstanceDefinitions def2){
        return new Product<>(run,def1,def2);
    }
    public static   Product of(Active a1, Active a2){
        return of(Tuple.tuple(a1.getSingle(),a2.getSingle()),a1.getDef1(),a2.getDef1());
    }
    public Coproduct coproduct(BiPredicate,Higher> test){
        return test.test(run._1(),run._2()) ?Coproduct.left(run._1(),def1,def2) : Coproduct.right(run._2(),def1,def2);
    }
    public Product filter(Predicate test) {
        return of(run.transform((m1, m2)->{
            Higher x2 = def2.monadZero().fold(p->p.filter(test,m2),()->m2);
            Higher x1 = def1.monadZero().fold(p->p.filter(test,m1),()->m1);
            return Tuple.tuple(x1, x2);
        }),def1,def2);
    }


    @Override
    public  Product ofType(Class type) {
        return (Product)Filters.super.ofType(type);
    }

    @Override
    public Product filterNot(Predicate predicate) {
        return filter(predicate.negate());
    }

    @Override
    public Product notNull() {
        return (Product)Filters.super.notNull();
    }

    public  Active zipWithSecond(BiFunction,? extends R> f) {
        return Active.of(def1.traverse().zipWith(def2.foldable(),f,run._1(),run._2()),def1);
    }
    public Product> zip(Product p2){
        return zip(p2,Tuple::tuple);
    }
    public Product> zip(Product p2, Product p3){
        return zip(p2,p3);
    }
    public  Product zip(Product p2, BiFunction zipper){
        Active a1 = Active.of(run._1(),def1);
        Active a2 = Active.of(p2.run._1(),def1);

        Active a3 = a1.zip(a2,zipper);

        Active b1 = Active.of(run._2(),def2);
        Active b2 = Active.of(p2.run._2(),def2);

        Active b3 = b1.zip(b2,zipper);

        return of(a3,b3);

    }
    public  Product zip(Product p2, Product p3, Function3 zipper){
        Active a1 = Active.of(run._1(),def1);
        Active a2 = Active.of(p2.run._1(),def1);
        Active a3 = Active.of(p3.run._1(),def1);

        Active a4 = a1.zip(a2,a3,zipper);

        Active b1 = Active.of(run._2(),def2);
        Active b2 = Active.of(p2.run._2(),def2);
        Active b3 = Active.of(p3.run._2(),def2);

        Active b4 = b1.zip(b2,b3,zipper);

        return of(a4,b4);
    }
    public  Product mapWithIndex(BiFunction f) {
        return of(Tuple.tuple(def1.traverse().mapWithIndex(f,run._1()),def2.traverse().mapWithIndex(f,run._2())),def1,def2);
    }
    public  Product> zipWithIndex() {
        return mapWithIndex(Tuple::tuple);
    }
    @Override
    public  Product map(Function fn) {

        return of(run.transform((m1, m2)->{
            Higher x2 = def2.functor().map(fn, m2);
            Higher x1 = def1.functor().map(fn, m1);
            return Tuple.tuple(x1, x2);
        }),def1,def2);
    }
    public  Product flatMap(Function> fn) {
        return of(map(fn).run.transform((m1, m2)->Tuple.tuple(def1.monad().flatMap(p->p.asTuple()._1(),m1),def2.monad().flatMap(p->p.asTuple()._2(),m2))),def1,def2);
    }


    @Override
    public Product peek(Consumer c) {
        return map(a->{
            c.accept(a);
            return a;
        });
    }

    @Override
    public String toString() {
        return "Product["+ run.toString()+"]";
    }



    public  Active tailRec1(T initial,Function>> fn){
        return asActiveTuple()._1().tailRec(initial, fn);
    }

    public  Active tailRec2(T initial,Function>> fn){
        return asActiveTuple()._2().tailRec(initial, fn);
    }


    public Active activeFirst(SemigroupK sg, Higher concat){
        return Active.of(sg.apply(run._1(),concat),def1);
    }
    public Active activeSecond(SemigroupK sg, Higher concat){
        return Active.of(sg.apply(run._2(),concat),def2);
    }

    public  R fold(BiFunction,? super Higher, ? extends R> visitor){
        return run.transform(visitor);
    }
    public  R visitA(BiFunction,? super Active, ? extends R> visitor){
        return run.transform((a, b)->visitor.apply(Active.of(a,def1),Active.of(b,def2)));
    }
    public Product plusFirst(SemigroupK semigroupK, Higher add){
        return of(Tuple.tuple(semigroupK.apply(run._1(),add),run._2()),def1,def2);
    }
    public Product plusSecond(SemigroupK semigroupK, Higher add){
        return of(Tuple.tuple(run._1(),semigroupK.apply(run._2(),add)),def1,def2);
    }
    public Product swap(){
        return of(run.swap(),def2,def1);
    }

    public Unfolds unfoldsDefault(){
        return new Unfolds(def1.unfoldable().fold(p->p,()->new Unfoldable.UnsafeValueUnfoldable<>()),
                def2.unfoldable().fold(p->p,()->new Unfoldable.UnsafeValueUnfoldable<>()));
    }

    public Maybe unfolds(){
        if(def1.unfoldable().isPresent() && def2.unfoldable().isPresent())
            return Maybe.just(new Unfolds(def1.unfoldable().orElse(null),def2.unfoldable().orElse(null)));
        return Maybe.nothing();
    }
    public Plus plusUnsafe(){
        return new Plus(def1.monadPlus().orElse(null),def2.monadPlus().orElse(null));
    }
    public Maybe plus(){
        if(def1.monadPlus().isPresent() && def2.monadPlus().isPresent())
            return Maybe.just(new Plus(def1.monadPlus().orElse(null),def2.monadPlus().orElse(null)));
        return Maybe.nothing();
    }
    @AllArgsConstructor
    public  class Unfolds {

        private final Unfoldable unf1;
        private final Unfoldable unf2;

        public  Product unfold(T b, Function>> fn){
            Tuple2, Higher> res = run.transform((left, right) -> Tuple.tuple(unf1.unfold(b, fn), unf2.unfold(b, fn)));
            return Product.of(res, def1, def2);
        }

        public  Product replicate(int n, T value) {
            return unfold(n,i -> Option.some(tuple(value, i-1)));
        }

        public  Product none() {
            return unfold((T) null, t -> Option.>none());
        }
        public  Product one(T a) {
            return replicate(1, a);
        }
    }
    @AllArgsConstructor
    public class Plus{
        private final MonadPlus plus1;
        private final MonadPlus plus2;

        public Product plus(Product a){
            Active r1 = Active.of(run._1(), def1).plus(plus1).plusA(a._1());
            Active r2 = Active.of(run._2(), def2).plus(plus2).plusA(a._2());
            return of(r1,r2);
        }
        public Product sum(ImmutableList> list){

            Active r1 = Active.of(run._1(), def1).plus(plus1).sumA(list.map(p->p.asActiveTuple()._1()));
            Active r2 = Active.of(run._2(), def2).plus(plus2).sumA(list.map(p->p.asActiveTuple()._2()));
            return of(r1,r2);
        }

    }
    public  R foldMap(final Monoid mb, final Function fn) {
        return run.transform((a, b) -> {
            R r1 = def1.foldable().foldMap(mb, fn, a);
            R r2 = def2.foldable().foldMap(mb, fn, b);
            return mb.foldRight(Arrays.asList(r2, r1));
        });
    }
    public T foldRight(Monoid monoid) {
        return run.transform((a, b) -> {
            T r1 = def1.foldable().foldRight(monoid, a);
            T r2 = def2.foldable().foldRight(monoid, b);
            return monoid.foldRight(Arrays.asList(r2, r1));
        });

    }

    public T foldRight(T identity, BinaryOperator semigroup) {
        return foldRight(Monoid.fromBiFunction(identity, semigroup));

    }
    public  Tuple2,LazySeq> toLazySeq(){
        return run.transform((a, b)->Tuple.tuple(def1.foldable().lazySeq(a),
            def2.foldable().lazySeq(b)));
    }
    public  Tuple2,Seq> toSeq(){
        return run.transform((a, b)->Tuple.tuple(def1.foldable().seq(a),
                def2.foldable().seq(b)));
    }
    public  Seq toSeqBoth(){
        return toSeq().transform((a, b)->a.plusAll(b));
    }
    public Tuple2,ReactiveSeq> stream(){
        return toLazySeq().transform((a, b)->Tuple.tuple(a.stream(),b.stream()));
    }
    public ReactiveSeq streamBoth(){
        return stream().transform((a, b)->a.appendStream(b));
    }

    public Product reverse(){
        return Product.of(run.transform((a, b)->Tuple.tuple(def1.traverse().reverse(a),def2.traverse().reverse(b))),def1,def2);
    }
    public  Tuple2 size() {
        return run.transform((a, b)->Tuple.tuple(def1.foldable().size(a),
                def2.foldable().size(b)));
    }
    public long totalSize() {
        return size().transform((a, b)->a+b);
    }

    public T foldLeft(Monoid monoid) {
        return run.transform((a, b) -> {
            T r1 = def1.foldable().foldRight(monoid, a);
            T r2 = def2.foldable().foldRight(monoid, b);
            return monoid.foldLeft(Arrays.asList(r1, r2));
        });
    }

    public T foldLeft(T identity, BinaryOperator semigroup) {
        return foldLeft(Monoid.fromBiFunction(identity, semigroup));
    }
    public  Tuple2 foldMapTuple(final Monoid mb, final Function fn) {
        return run.transform((a, b) -> {
            R r1 = def1.foldable().foldMap(mb, fn, a);
            R r2 = def2.foldable().foldMap(mb, fn, b);
            return Tuple.tuple(r2, r1);
        });
    }
    public Tuple2 foldRightTuple(Monoid monoid) {
        return run.transform((a, b) -> {
            T r1 = def1.foldable().foldRight(monoid, a);
            T r2 = def2.foldable().foldRight(monoid, b);
            return Tuple.tuple(r2, r1);
        });

    }

    public Tuple2 foldRightTuple(T identity, BinaryOperator semigroup) {
        return foldRightTuple(Monoid.fromBiFunction(identity, semigroup));

    }

    public Tuple2 foldLeftTuple(Monoid monoid) {
        return run.transform((a, b) -> {
            T r1 = def1.foldable().foldRight(monoid, a);
            T r2 = def2.foldable().foldRight(monoid, b);
            return Tuple.tuple(r1, r2);
        });
    }

    public Tuple2 foldLeftTuple(T identity, BinaryOperator semigroup) {
        return foldLeftTuple(Monoid.fromBiFunction(identity, semigroup));
    }


    public  Product forEach2(Function> value1, final BiFunction yieldingFunction) {
        return flatMap(a->{
            return value1.apply(a).map(b->yieldingFunction.apply(a,b));
        });

    }
    public  Product forEach3(final Function> value1, final BiFunction> value2,
                                                     final Function3 yieldingFunction) {
        return flatMap(a->{
            return value1.apply(a).flatMap(b->value2.apply(a,b).map(c->yieldingFunction.apply(a,b,c)));
        });
    }
    public  Product forEach4(final Function> value1, final BiFunction> value2, final Function3> value3,
                                                         final Function4 yieldingFunction) {
        return flatMap(a->{
            return value1.apply(a).flatMap(b->value2.apply(a,b).flatMap(c->value3.apply(a,b,c).map(d->yieldingFunction.apply(a,b,c,d))));
        });
    }

    public static  Product narrowK(Higher, W2>, T> ds){
        return (Product)ds;
    }


    public  Active,W2>,T> allTypeClasses(){
        return  Active.of(this, Instances.definitions(def1, def2));
    }

    public  Higher> traverseA(Applicative applicative, Function> fn){
        return traverseA(applicative,fn,this);

    }

    public static  Higher> traverseA(Applicative applicative, Function> fn,Product n){

        Higher> v1 = n._1().traverseA(applicative, fn);

        Higher> v2 = n._2().traverseA(applicative, fn);


        return applicative.zip(v1,v2,(a,b)->a.concat(b));
    }
    public   Higher> sequenceA(Applicative applicative,
                                                     Product> ds){
        return traverseA(applicative, i -> i, ds);

    }

    public    Higher> flatTraverseA(Applicative applicative,
                                                           Function>> f) {
        return applicative.map_(traverseA(applicative, f), it->  it.flatMap(a->a));
    }

    public   Higher> flatSequenceA(Applicative applicative, Product>> fgfa) {
        return applicative.map(i -> i.flatMap(Function.identity()),sequenceA(applicative, fgfa) );
    }


    @AllArgsConstructor(access = AccessLevel.PRIVATE)
    public static class Instances implements InstanceDefinitions, W2>>{
        private final InstanceDefinitions def1;
        private final InstanceDefinitions def2;


        public static  InstanceDefinitions, W2>> definitions(InstanceDefinitions def1,InstanceDefinitions def2){
            return new Instances<>(def1,def2);
        }

        public  Functor, W2>> functor(){
            return new Functor, W2>>(){

                @Override
                public  Higher, W2>, R> map(Function fn, Higher, W2>, T> ds) {
                    return narrowK(ds).map(fn);
                }
            };
        }
        public Pure, W2>> unit(){
            return new Pure, W2>>(){

                @Override
                public  Higher, W2>, T> unit(T value) {
                    return Product.of(Active.of(def1,value), Active.of(def2, value));

                }
            };
        }

        public  Applicative, W2>> applicative(){
            return new Applicative, W2>>(){

                @Override
                public  Higher, W2>, R> ap(Higher, W2>, ? extends Function> fn, Higher, W2>, T> apply) {
                    return narrowK(fn).flatMap(x -> narrowK(apply).map(x));

                }

                @Override
                public  Higher, W2>, R> map(Function fn, Higher, W2>, T> ds) {
                    return functor().map(fn,ds);
                }

                @Override
                public  Higher, W2>, T> unit(T value) {
                    return Instances.this.unit().unit(value);
                }
            };
        }
        public Monad, W2>> monad(){
            return new Monad, W2>>(){

                @Override
                public  Higher, W2>, R> ap(Higher, W2>, ? extends Function> fn, Higher, W2>, T> apply) {
                    return applicative().ap(fn,apply);
                }

                @Override
                public  Higher, W2>, R> map(Function fn, Higher, W2>, T> ds) {
                    return functor().map(fn,ds);
                }

                @Override
                public  Higher, W2>, T> unit(T value) {
                    return Instances.this.unit().unit(value);
                }

                @Override
                public  Higher, W2>, R> flatMap(Function, W2>, R>> fn, Higher, W2>, T> ds) {
                    return narrowK(ds).flatMap(fn.andThen(Product::narrowK));
                }
            };
        }

        @Override
        public  Option, W2>>> monadZero() {
            return def1.monadZero().flatMap(x->{
                return def2.monadZero().map(y->{
                return new MonadZero, W2>>() {
                    @Override
                    public  Higher, W2>, R> ap(Higher, W2>, ? extends Function> fn, Higher, W2>, T> apply) {
                        return applicative().ap(fn,apply);
                    }

                    @Override
                    public  Higher, W2>, R> map(Function fn, Higher, W2>, T> ds) {
                        return functor().map(fn,ds);
                    }

                    @Override
                    public  Higher, W2>, T> filter(Predicate predicate, Higher, W2>, T> ds) {
                        return narrowK(ds).filter(predicate);
                    }

                    @Override
                    public Higher, W2>, ?> zero() {

                        Active ac1 = Active.of( def1.monadZero().orElse(null).zero(), def1);
                        Active ac2 = Active.of(def2.monadZero().orElse(null).zero(), def2);
                        return Product.of(ac1, ac2);

                    }

                    @Override
                    public  Higher, W2>, T> unit(T value) {
                        return Instances.this.unit().unit(value);
                    }

                    @Override
                    public  Higher, W2>, R> flatMap(Function, W2>, R>> fn, Higher, W2>, T> ds) {
                        return monad().flatMap(fn,ds);
                    }
                };});
            });
        }
        public  MonadRec, W2>> monadRec() {

            return new MonadRec, W2>>(){
                @Override
                public  Higher, W2>, R> tailRec(T initial, Function, W2>, ? extends Either>> fn) {
                    Product> next[] = new Product[1];
                    Either in = Either.left(initial);

                    next[0] = Product.of(Tuple.tuple(def1.unit().unit(in),def2.unit().unit(in)),def1,def2);
                    boolean cont = true;
                    do {
                        cont = next[0].fold( (a, __) -> {
                            boolean[] internalCont = {true};

                            Higher b = a;
                            Higher r = def1.functor().map(p -> {
                                Either x = (Either) p;
                                internalCont[0] = internalCont[0] || x.fold(s -> {
                                    next[0] = narrowK(fn.apply(s));
                                    return true;
                                }, pr -> false);
                                return internalCont[0];
                            }, a);
                            return internalCont[0];

                        });
                    } while (cont);
                    return next[0].map(x->x.orElse(null));
                }

            };


        }
        @Override
        public  Option, W2>>> monadPlus() {
            return def1.monadPlus().flatMap(x -> {
                return def2.monadPlus().map(y -> {
                    return new MonadPlus, W2>>() {

                        @Override
                        public  Higher, W2>, R> ap(Higher, W2>, ? extends Function> fn, Higher, W2>, T> apply) {
                            return applicative().ap(fn, apply);
                        }

                        @Override
                        public  Higher, W2>, R> map(Function fn, Higher, W2>, T> ds) {
                            return functor().map(fn, ds);
                        }

                        @Override
                        public  Higher, W2>, T> unit(T value) {
                            return Instances.this.unit().unit(value);
                        }

                        @Override
                        public  Higher, W2>, R> flatMap(Function, W2>, R>> fn, Higher, W2>, T> ds) {
                            return monad().flatMap(fn, ds);
                        }

                      @Override
                      public  MonoidK, W2>> monoid() {
                        return new MonoidK, W2>>() {
                          @Override
                          public  Higher, W2>, T> zero() {
                            return monadZero().orElse(null).zero();
                          }

                          @Override
                          public  Higher, W2>, T> apply(Higher, W2>, T> a, Higher, W2>, T> b) {
                            Product p1 = narrowK(a);
                            Product p2 = narrowK(b);
                            return p1.zip((Product) p2);
                          }
                        };
                      }




                    };
                });
            });
        }

        @Override
        public  Option, W2>>> monadPlus(MonoidK, W2>> m) {
            return def1.monadPlus().flatMap(x -> {
                return def2.monadPlus().map(y -> {
                    return new MonadPlus, W2>>() {

                        @Override
                        public  Higher, W2>, R> ap(Higher, W2>, ? extends Function> fn, Higher, W2>, T> apply) {
                            return applicative().ap(fn, apply);
                        }

                        @Override
                        public  Higher, W2>, R> map(Function fn, Higher, W2>, T> ds) {
                            return functor().map(fn, ds);
                        }

                        @Override
                        public  Higher, W2>, T> unit(T value) {
                            return Instances.this.unit().unit(value);
                        }

                        @Override
                        public  Higher, W2>, R> flatMap(Function, W2>, R>> fn, Higher, W2>, T> ds) {
                            return monad().flatMap(fn, ds);
                        }

                      @Override
                      public  MonoidK, W2>> monoid() {
                        return m;
                      }

                    };
                });
            });
        }

        @Override
        public  Traverse, W2>> traverse() {
            return new Traverse, W2>>() {
                @Override
                public  Higher, W2>, R>> traverseA(Applicative applicative, Function> fn, Higher, W2>, T> ds) {
                    Product pr = narrowK(ds);
                    Higher> x = pr.traverseA(applicative, fn);
                    return (Higher)x;
                }

                @Override
                public  Higher, W2>, T>> sequenceA(Applicative applicative, Higher, W2>, Higher> ds) {
                    return traverseA(applicative,Function.identity(),ds);
                }

                @Override
                public  Higher, W2>, R> ap(Higher, W2>, ? extends Function> fn, Higher, W2>, T> apply) {
                    return Instances.this.applicative().ap(fn,apply);
                }

                @Override
                public  Higher, W2>, T> unit(T value) {
                    return Instances.this.unit().unit(value);
                }

                @Override
                public  Higher, W2>, R> map(Function fn, Higher, W2>, T> ds) {
                    return Instances.this.functor().map(fn,ds);
                }
            };
        }
        @Override
        public  Foldable, W2>> foldable() {
                return new Foldable, W2>>(){

                        @Override
                        public  T foldRight(Monoid monoid, Higher, W2>, T> ds) {
                            Product p = narrowK(ds);
                            return p.foldRight(monoid);
                        }

                        @Override
                        public  T foldLeft(Monoid monoid, Higher, W2>, T> ds) {
                            Product p = narrowK(ds);
                            return p.foldLeft(monoid);
                        }

                    @Override
                    public  R foldMap(Monoid mb, Function fn, Higher, W2>, T> nestedA) {
                        return foldLeft(mb,narrowK(nestedA).map(fn));
                    }
                };
        }

        @Override
        public  Option, W2>>> comonad() {
            return Maybe.nothing();
        }



        @Override
        public  Option, W2>>> unfoldable() {
            if(!def1.unfoldable().isPresent() && !def2.unfoldable().isPresent())
                return Maybe.nothing();
            return Maybe.just(new  Unfoldable, W2>>(){

                @Override
                public  Higher, W2>, R> unfold(T b, Function>> fn) {
                    Higher a1 = def1.unfoldable().orElse(null).unfold(b, fn);
                    Higher a2 = def2.unfoldable().orElse(null).unfold(b, fn);
                    return Product.of(Tuple.tuple(a1,a2),def1,def2);

                }
            });
        }
    }





}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy