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

cyclops.free.Cofree Maven / Gradle / Ivy

The newest version!
package cyclops.free;


import com.oath.cyclops.hkt.Higher;
import com.oath.cyclops.hkt.Higher2;

import com.oath.cyclops.hkt.DataWitness.cofree;
import com.oath.cyclops.hkt.DataWitness.eval;
import cyclops.control.Eval;
import cyclops.function.NaturalTransformation;
import cyclops.instances.control.EvalInstances;
import cyclops.typeclasses.comonad.Comonad;
import cyclops.typeclasses.functor.Functor;
import cyclops.typeclasses.monad.Monad;
import cyclops.typeclasses.monad.Traverse;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;

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

/*
 * Cofree refs & guides : https://github.com/typelevel/cats/blob/master/free/src/main/scala/cats/free/Cofree.scala
 *                        https://github.com/kategory/kategory/blob/master/kategory/src/main/kotlin/kategory/free/Cofree.kt
 *
 */
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Cofree implements Supplier, Higher2 {

    private final Functor functor;
    private final T head;
    private final Eval>> tail;

    public static  Cofree of(Functor functor, T head, Eval>> tail) {
        return new Cofree(functor,head,tail);
    }
    public Higher> tailForced() {
        return tail.get();
    }
    public  Cofree map(Function f){
        return transform(f,c->c.map(f));
    }
    public  Cofree  coflatMap(Function,? extends  R> f){
        return of(functor, f.apply(this), tail.map(h-> functor.map_(h, __->coflatMap(f))));
    }
    public Cofree> nest() {
        return of(functor, this, tail.map(h-> functor.map_(h, __-> nest())));
    }

    public  Cofree transform(Function f, Function,Cofree> g) {
        return of(functor,f.apply(head),tail.map(i-> functor.map_(i,g)));
    }
    public Cofree mapBranchingRoot(NaturalTransformation nat) {
        return of(functor, head, tail.map(h->nat.apply(h)));
    }
    public  Cofree mapBranchingS(Functor functor,NaturalTransformation nat) {
        return of(functor, head, tail.map(ce -> nat.apply(this.functor.map_(ce, cofree -> cofree.mapBranchingS( functor,nat)))));
    }
    public  Cofree  mapBranchingT(Functor functor,NaturalTransformation nat) {
        return of(functor, head, tail.map(ce -> functor.map_(nat.apply(ce), cofree -> cofree.mapBranchingT(functor,nat))));
    }
    public Cofree forceTail() {
       return of(functor, head, Eval.now(tail.get()));
    }

    public Cofree forceAll(){
        return of(functor, head, Eval.now(tail.map(h-> functor.map_(h, c->c.forceAll())).get()));
    }
    public T extract(){
        return head;
    }

    public T get(){
        return extract();
    }

    public   Eval fold(Traverse traverse, BiFunction,Eval> fn) {
        Eval> eval = traverse.traverseA(EvalInstances.applicative(), it -> it.fold( traverse,fn), tailForced())
                .convert(Eval::narrowK);
        return eval.flatMap(i->fn.apply(extract(), i));
    }

    public   Higher visitM(Traverse traverse, Monad monad,BiFunction,Higher> fn,
                                      NaturalTransformation inclusion) {

        class inner {

            public Eval> loop(Cofree eval) {
                Higher> looped = traverse.traverseA(monad, (Cofree fr) ->  monad.flatten(inclusion.apply(Eval.defer(()->loop(fr)))), eval.tailForced());
                Higher folded = monad.flatMap_(looped, fb -> fn.apply(eval.head, fb));
                return Eval.now(folded);
            }
        }
        return monad.flatten(inclusion.apply(new inner().loop(this)));
     }
        public static  Cofree unfold(Functor functor,T b, Function> fn) {
            return of(functor, b, Eval.later(() -> functor.map_(fn.apply(b), t -> unfold(functor, t, fn))));
        }

    public static  Cofree narrowK2(final Higher2 cof) {
        return (Cofree)cof;
    }
    public static  Cofree narrowK(final Higher,T> cof) {
        return (Cofree)cof;
    }
    public static class Instances{
        public  Comonad> comonad(){
            return new Comonad>() {
                @Override
                public  T extract(Higher, T> ds) {
                    return narrowK(ds).extract();
                }

                @Override
                public  Higher, Higher, T>> nest(Higher, T> ds) {

                    return (Higher)narrowK(ds).nest();
                }

                @Override
                public  Higher, R> coflatMap(Function, T>, R> mapper, Higher, T> ds) {
                    return narrowK(ds).coflatMap(mapper);
                }


            };
        }
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy