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

cyclops.arrow.Kleisli Maven / Gradle / Ivy

The newest version!
package cyclops.arrow;

import com.oath.cyclops.hkt.Higher;
import com.oath.cyclops.hkt.Higher3;
import com.oath.cyclops.types.functor.Transformable;
import cyclops.control.Either;
import cyclops.function.Function1;
import cyclops.function.Function3;
import cyclops.function.Function4;


import cyclops.typeclasses.Do;
import cyclops.typeclasses.Do.Do1;
import cyclops.typeclasses.monad.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import cyclops.data.tuple.Tuple;
import cyclops.data.tuple.Tuple2;

import java.util.function.BiFunction;
import java.util.function.Function;


import com.oath.cyclops.hkt.DataWitness.kleisli;


/**
 * Compose arrow that return monads
 *
 * @param  Monad kind
 * @param  Function input type
 * @param  Function return type
 *              (inside monad e.g. Kleisli[stream,String,Integer] represents a function that takes a String and returns a Stream of Integers)
 */

@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Kleisli implements Function1>,
                                        Transformable,
                                        Higher3 {

    private final Monad monad;

    private final Function> fn;

    public static  Kleisli of(Monad monad, Function> fn){
        return new Kleisli(monad,fn);
    }

    public static  Kleisli arrow(Monad monad, Function fn){
       return of(monad,a -> monad.unit(fn.apply(a)));
    }
    public Do.Do1 doWith(T t){
        return Do.forEach(monad).__(()->narrow(fn).apply(t));
    }
    public Kleisli local(Function local){
        return kleisliK(monad, t->monad.map(r->local.apply(r),apply(t)));
    }
    public  Kleisli map(Function mapper){
        return kleisliK(monad,andThen(am->monad.map(mapper,am)));
    }
    public  Kleisli flatMap(Function> mapper){
      Function> fn = (Function>)mapper;
      Kleisli x = kleisliK(monad, andThen(am -> monad.flatMap(fn, am)));
      return x;
    }
    public   Kleisli> zip(Kleisli o){
        return zip(o, Tuple::tuple);
    }
    public   Kleisli zip(Kleisli o, BiFunction fn){
        return flatMapK(a -> o.map(b -> fn.apply(a,b)));
    }

    public  Kleisli flatMapK(Function> mapper){
        return kleisliK(monad, t->monad.flatMap(r ->  mapper.apply(r).apply(t),apply(t)));
    }

    public  Kleisli compose(Kleisli kleisli) {
        return of(monad,a -> monad.flatMap(this,kleisli.apply(a)));
    }
    public  Kleisli then(Kleisli kleisli) {
        return of(monad,t-> monad.flatMap(kleisli,apply(t)));

    }

    public <__> Kleisli, Either> leftK(W type) {
        return kleisliK(monad, xr -> xr.fold(l -> monad.map(Either::left,apply(l)), r -> monad.map(Either::right,monad.unit(r))));
    }
    public <__> Kleisli, Either<__,R>> rightK(W type) {
        return kleisliK(monad, xr -> xr.fold(l -> monad.map(Either::left,monad.unit(l)), r -> monad.map(Either::right,apply(r))));
    }
    public <__> Kleisli, Tuple2> firstK() {
        return kleisliK(monad, xr -> xr.transform((v1, v2) -> monad.map(r1-> Tuple.tuple(r1,v2),apply(v1))));
    }
    public <__> Kleisli, Tuple2<__,R>> secondK() {
        return kleisliK(monad, xr -> xr.transform((v1, v2) -> monad.map(r2-> Tuple.tuple(v1,r2),apply(v2))));
    }


    public  Kleisli, Either> merge(Kleisli merge, W type) {
        Kleisli> first = then(lift(monad, Either::left, type));
        Kleisli> second = merge.then(lift(monad, Either::right, type));
        return first.fanIn(second);

    }


    public  Kleisli, R> fanIn(Kleisli fanIn) {
        return of(monad,e -> e.fold(this, fanIn));
    }



    public  Kleisli forEach4(Function>> value2,
                                                     BiFunction>> value3,
                                                     Function3>> value4,
                                                     Function4 yieldingFunction) {




        return this.flatMapK(in -> {

            Kleisli a = kleisliK(monad,value2.apply(in));
            return a.flatMapK(ina -> {
                Kleisli b = kleisliK(monad,value3.apply(in,ina));
                return b.flatMapK(inb -> {

                    Kleisli c = kleisliK(monad,value4.apply(in,ina,inb));
                    return c.map(inc->yieldingFunction.apply(in, ina, inb, inc));

                });


            });


        });

    }




    public  Kleisli forEach3(Function>> value2,
                                                 BiFunction>> value3,
                                                 Function3 yieldingFunction) {

        return this.flatMapK(in -> {

            Kleisli a = kleisliK(monad,value2.apply(in));
            return a.flatMapK(ina -> {
                Kleisli b = kleisliK(monad,value3.apply(in,ina));
                return b.map(in2 -> {
                    return yieldingFunction.apply(in, ina, in2);

                });



            });

        });

    }

    public  Kleisli forEach2(Function>> value2,
                                             BiFunction yieldingFunction) {

        return this.flatMapK(in -> {

            Kleisli a = kleisliK(monad,value2.apply(in));
            return a.map(in2 -> {
                return yieldingFunction.apply(in, in2);

            });




        });


    }
    public  Kleisli forEachK4(Function> value2,
                                                     BiFunction> value3,
                                                     Function3> value4,
                                                     Function4 yieldingFunction) {




        return this.flatMapK(in -> {

            Kleisli a = value2.apply(in);
            return a.flatMapK(ina -> {
                Kleisli b = value3.apply(in,ina);
                return b.flatMapK(inb -> {

                    Kleisli c = value4.apply(in,ina,inb);
                    return c.map(inc->yieldingFunction.apply(in, ina, inb, inc));

                });


            });


        });

    }




    public  Kleisli forEachK3(Function> value2,
                                                 BiFunction> value3,
                                                 Function3 yieldingFunction) {

        return this.flatMapK(in -> {

            Kleisli a = value2.apply(in);
            return a.flatMapK(ina -> {
                Kleisli b = value3.apply(in,ina);
                return b.map(in2 -> {
                    return yieldingFunction.apply(in, ina, in2);

                });



            });

        });

    }

    public  Kleisli forEachK2(Function> value2,
                                             BiFunction yieldingFunction) {

        return this.flatMapK(in -> {

            Kleisli a = value2.apply(in);
            return a.map(in2 -> {
                return yieldingFunction.apply(in, in2);

            });

        });


    }


    public static  Kleisli kleisliK(Monad monad, Function> fn){
        return of(monad,fn);
    }
    public static  Kleisli lift(Monad monad, Function fn, W type){
        return  kleisliK(monad,fn.andThen(r->monad.unit(r)));
    }

    public static  Function1> narrow(Function> fn) {
        if(fn instanceof Function1){
            return (Function1)fn;
        }
        return in -> (Higher)fn.apply(in);
    }

    public static  Kleisli narrowK(Higher, T>, R> k) {

        return (Kleisli)k;
    }

    public static  Kleisli narrowK3(Higher3 kleisliHigher3) {

        return (Kleisli)kleisliHigher3;
    }

    @Override
    public Higher apply(T a) {
        return (Higher)fn.apply(a);
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy