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

cyclops.hkt.Active Maven / Gradle / Ivy

There is a newer version: 10.4.1
Show newest version
package cyclops.hkt;


import com.oath.cyclops.hkt.Higher;
import com.oath.cyclops.types.Filters;
import com.oath.cyclops.types.foldable.To;
import com.oath.cyclops.types.functor.Transformable;
import cyclops.arrow.*;
import cyclops.data.LazySeq;
import cyclops.control.*;
import cyclops.control.Maybe;
import cyclops.data.ImmutableList;
import cyclops.function.*;
import cyclops.reactive.ReactiveSeq;
import cyclops.typeclasses.Comprehensions;
import cyclops.typeclasses.InstanceDefinitions;
import cyclops.typeclasses.foldable.Foldable;
import cyclops.typeclasses.foldable.Unfoldable;
import cyclops.typeclasses.monad.Applicative;
import cyclops.typeclasses.monad.MonadPlus;
import cyclops.typeclasses.monad.MonadZero;
import cyclops.typeclasses.monad.Traverse;
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.function.*;

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

/**
 * Provide easy access to all typeclasses for a type
 * e.g.
 *
 * 
 *     {@code
 *       Active active = Active.of(ListX.of(1,2,3),ListX.Instances.definitions());
 *       Active doubled = active.map(i->i*2);
 *       Active doubledPlusOne = doubled.flatMap(i->ListX.of(i+1));
 *     }
 *
 * 
* * @param Witness type * @param Data type */ @AllArgsConstructor(access= AccessLevel.PRIVATE) @EqualsAndHashCode(of={"single"}) public class Active implements Filters, Transformable, To> { @Getter private final Higher single; @Getter private final InstanceDefinitions def1; public static Active of(Higher single, InstanceDefinitions def1) { return new Active<>(single, def1); } public static Active of(Function> single, C c,InstanceDefinitions def1) { return of(single.apply(c),def1); } public static Active of(InstanceDefinitions def1,T value) { return new Active<>(def1.unit().unit(value), def1); } /** * Perform a custom operation * *
     *     {@code
     *       Active active = Active.of(ListX.of(1,2,3), ListX.Instances.definitions());
     *      Active> grouped = active.custom(ListX::narrowK, l -> l.grouped(10));
     *     }
     * 
* * @param narrow Function that narrows Higher Kinded encoding to it's concrete type * @param fn Transformation function * @param Concrete type * @param Return type * @return Transformed Active after custom operation */ public Active custom(Function,? extends S> narrow,Function> fn){ return Active.of(fn.apply(narrow.apply(single)),def1); } /** * Convert this Active to a new type via the underlying concrete type * e.g. Given an Active List *
     *     {@code
     *     Active active = Active.of(ListX.of(1,2,3), ListX.Instances.definitions());
     *     }
     * 
* * We can convert it to a set via concreteConversion * *
     *     {@code
     *      SetX set = active.concreteConversion(ListX.kindCokleisli())
                                      .to(ListX::toSetX());
     *     }
     * 
* Most cyclops-react types provide kindCokleisli implementations that convert a Higher Kinded encoding of the type * back to the concrete type * * @param narrow Narrowing function (Cokleisli) to a concrete type * @param Concrete type * @param Return type * @return Converter that works on the concrete type */ public Converter concreteConversion(Function,? extends S> narrow){ return new Converter(){ @Override public R to(Function fn) { return fn.apply(narrow.apply(single)); } }; } public static interface Converter{ public R to(Function fn); } public R fold(Function,? extends C> narrow, Function visitor){ return visitor.apply(narrow.apply(single)); } public R fold(Function,? extends R> visitor){ return visitor.apply(single); } public R visitA(Function,? extends R> visitor){ return visitor.apply(this); } public Higher getActive() { return single; } public Active unit(R value) { return of(def1.unit().unit(value), def1); } public Active filter(Predicate predicate) { return of(def1.monadZero().fold(s -> s.filter(predicate, single), () -> single), def1); } public Active> zip(Higher fb) { return of(def1.applicative().zip(single,fb),def1); } public Active mapK(FunctionK fn) { return of( fn.apply(single), fn.definitions()); } public Active map(Function fn) { return of(def1.functor().map(fn, single), def1); } public Active mapWithIndex(BiFunction f) { return of(def1.traverse().mapWithIndex(f,single),def1); } public T intercalate(Monoid monoid, T value) { return def1.foldable().intercalate(monoid,value,single); } public boolean anyMatch(Predicate pred){ return def1.foldable().anyMatch(pred,single); } public boolean allMatch(Predicate pred){ return def1.foldable().allMatch(pred,single); } public Option getAt(int index){ return toLazySeq().get(index); } public Active reverse(){ return of(def1.traverse().reverse(single),def1); } public LazySeq toLazySeq(){ return def1.foldable().lazySeq(single); } public ReactiveSeq stream(){ return toLazySeq().stream(); } public long size() { return def1.foldable().size(single); } public Active> zipWithIndex() { return of(def1.traverse().zipWithIndex(single),def1); } public Active zipWith(Active a, BiFunction,? extends R> f) { return of(def1.traverse().zipWith(a.def1.foldable(),f,single,a.single),def1); } public Active zipWith(Foldable foldable,Higher a, BiFunction,? extends R> f) { return of(def1.traverse().zipWith(foldable,f,single,a),def1); } public Narrowed concreteMonoid(Kleisli widen, Cokleisli narrow){ return new Narrowed(widen,narrow); } /** * Use concreteFlatMap to access a flatMap operator that works with the concrete type (rather than the higher kind encoding) * * e.g. using a vavr Vector * *
     *     {@code
     *     Active vector = Vectors.allTypeclasses(Vector.of(1,2,3));
     *
     *     vector.concreteFlatMap(Vectors.kindKleisli())
                .flatMap(i->Vector.of(1,2,3)); //flatMap accepts Vector rather than Higher
     *
     *     }
     * 
* * Note this is not typically needed for cyclops-react types * * */ 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); } @AllArgsConstructor public class NarrowedFlatMap{ private final Kleisli narrow; public Active flatMap(Function fn) { return Active.this.flatMap(fn.andThen(narrow)); } public Active zip(C fb, BiFunction f) { return Active.this.zip(narrow.apply(fb),f); } public Active> zip(C fb) { return Active.this.zip(narrow.apply(fb)); } } @AllArgsConstructor public class NarrowedTailRec{ private final Kleisli> narrow; public Active tailRec(T initial,Function fn){ return of(def1.monadRec().tailRec(initial,fn.andThen(r->narrow.apply(r))),def1); } } @AllArgsConstructor public class NarrowedApplicative{ private final Kleisli> narrow; public Active ap(C fn) { return of(def1.applicative().ap(narrow.apply(fn), single), def1); } } @AllArgsConstructor public class Narrowed{ //plus, sum private final Kleisli widen; private final Cokleisli narrow; public C extract(){ return narrow.apply(single); } public Active plus(Monoid m,C add){ return sum(m,LazySeq.of(add)); } public Active sum(C seed, BinaryOperator op,ImmutableList list){ C res =list.plus(narrow.apply(single)).foldLeft(seed,(a,b)->op.apply(a,b)); return of(widen.apply(res),def1); } public Active sum(Monoid s,ImmutableList list){ C res =list.plus(narrow.apply(single)).foldLeft(s.zero(),(a,b)->s.apply(a,b)); return of(widen.apply(res),def1); } public Active sumInverted(Group s, ImmutableList list){ C res = s.invert(list.plus(narrow.apply(single)).foldLeft(s.zero(),(a,b)->s.apply(a,b))); return of(widen.apply(res),def1); } public Maybe> sum(ImmutableList list){ return Active.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 Active zip(Higher fb, BiFunction f) { return of(def1.applicative().zip(single,fb,f),def1); } public Eval> lazyZip(Eval> lazy, BiFunction fn) { return lazy.map(e-> zip(e,fn)); } public Eval> lazyZipA(Eval> lazy, BiFunction fn) { return lazy.map(e->zip(e.getSingle(),fn)); } public Active peek(Consumer fn) { return of(def1.functor().peek(fn, single), def1); } public Function, Active> lift(final Function fn) { return t -> of(def1.functor().map(fn, t.single), def1); } public Active> zip(Active p2){ return zip(p2, Tuple::tuple); } public Active zip(Active p2,BiFunction zipper){ Applicative ap = def1.applicative(); Function> fn = a->b->zipper.apply(a,b); Higher>> hfn = ap.unit(fn); return of(ap.ap(ap.ap(hfn,single),p2.getSingle()),def1); } public Active> zip(Active p2, Active p3){ return zip(p2, p3,Tuple::tuple); } public Active zip(Active p2,Active p3,Function3 zipper){ Applicative ap = def1.applicative(); Function>> fn = a->b->c->zipper.apply(a,b,c); Higher>>> hfn = ap.unit(fn); return of(ap.ap(ap.ap(ap.ap(hfn,single),p2.getSingle()),p3.getSingle()),def1); } public Active flatMap(Function> fn) { return of(def1.monad().flatMap(fn, single), def1); } public Active flatMapA(Function> fn) { return of(def1.monad().flatMap(fn.andThen(Active::getActive), single), def1); } public Active ap(Higher> fn) { return of(def1.applicative().ap(fn, single), def1); } public Active ap(C c,Function>> fn) { return ap(fn.apply(c)); } public Active plus(SemigroupK semigroupK, Higher add){ return of(semigroupK.apply(single,add),def1); } public Active plus(SemigroupK semigroupK, Active add){ return of(semigroupK.apply(single,add.getSingle()),def1); } public Unfolds unfolds(Unfoldable unfoldable){ return new Unfolds(unfoldable); } public Plus plus(MonadPlus plus){ return new Plus(plus); } public Unfolds unfoldsDefault(){ return new Unfolds(def1.unfoldable().fold(p->p,()->new Unfoldable.UnsafeValueUnfoldable<>())); } public Maybe unfolds(){ return def1.unfoldable().fold(e->Maybe.just(new Unfolds(e)),Maybe::nothing); } public Maybe plus(){ return def1.monadPlus().fold(e->Maybe.just(new Plus(e)),Maybe::nothing); } @AllArgsConstructor public class Plus{ private final MonadPlus monadPlus; public MonoidK monoidK(){ return monadPlus.monoid(); } public Monoid> monoid(){ return monadPlus.monoid().asMonoid(); } public Active zero(){ Higher h = monadPlus.zero(); return of(h, def1); } public Active sum(ImmutableList> list){ return of(monadPlus.sum(list.plus(single)),def1); } public Active sumA(ImmutableList> list){ return sum(list.map(Active::getActive)); } public Active plus(Higher a){ return of(monadPlus.plus(single,a),def1); } public Active plusA(Active ac){ Higher a =ac.single; return plus(a); } } public Active tailRec(T initial,Function>> fn){ return of(def1.monadRec().tailRec(initial,fn),def1); } public Active tailRecA(T initial,Function>> fn){ return of(def1.monadRec().tailRec(initial,fn.andThen(Active::getActive)),def1); } @AllArgsConstructor public class Unfolds{ private final Unfoldable unfoldable; public Active unfold(T b, Function>> fn){ return of(unfoldable.unfold(b,fn),def1); } public Active replicate(long n, T value) { return unfold(n,i -> i>0? Option.some(tuple(value, i Nested replicate(Function fn, Function mapper) { return Nested.of(def1.functor().map(value->replicate(fn.apply(value), mapper.apply(value)).getSingle(),single),def1,def1); } public Nested replicate(long n) { return Nested.of(def1.functor().map(value->replicate(n,value).getSingle(),single),def1,def1); } public Active cycle(T value) { return replicate(Long.MAX_VALUE, value); } public Active none() { return unfold((T) null, t -> Option.>none()); } public Active one(T a) { return replicate(1, a); } } public R foldMap(final Monoid mb, final Function fn) { return def1.foldable().foldMap(mb,fn,single); } public T foldRight(Monoid monoid) { return def1.foldable().foldRight(monoid, single); } public T foldRight(T identity, BinaryOperator semigroup) { return foldRight(Monoid.fromBiFunction(identity, semigroup)); } public T foldLeft(Monoid monoid) { return def1.foldable().foldLeft(monoid, single); } public T foldLeft(T identity, BinaryOperator semigroup) { return foldLeft(Monoid.fromBiFunction(identity, semigroup)); } public Higher> flatTraverse(Applicative applicative, Function>>f) { return def1.traverse() .flatTraverse(applicative,def1.monad(),single,f); } public Higher> traverseA(Applicative applicative, Function> fn){ return traverseA(applicative,fn,this); } public static Higher> traverseA(Applicative applicative, Function> fn,Active n){ Traverse traverse = n.def1.traverse(); Higher> r = traverse.traverseA(applicative,fn,n.single); Higher> x = applicative.map(nr -> Active.of(nr, n.def1), r); return x; } public Higher> sequenceA(Applicative applicative, Active> ds){ return traverseA(applicative, i -> i, ds); } public Higher> flatTraverseA(Applicative applicative, Function>> f) { return applicative.map_(traverseA(applicative, f), it-> it.flatMapA(a->a)); } public Higher> flatSequenceA(Applicative applicative, Active>> fgfa) { return applicative.map(i -> i.flatMapA(Function.identity()),sequenceA(applicative, fgfa) ); } public Product concat(Active active){ return Product.of(this,active); } @Override public Active ofType(Class type) { return (Active)Filters.super.ofType(type); } @Override public Active filterNot(Predicate predicate) { return (Active)Filters.super.filterNot(predicate); } @Override public Active notNull() { return (Active)Filters.super.notNull(); } public Active forEach4(final Function> value1, final BiFunction> value2, final Function3> value3, final Function4 yieldingFunction) { return of(Comprehensions.of(def1.monad()).forEach4(this.single,value1,value2,value3,yieldingFunction),def1); } public Maybe> forEach4(final Function> value1, final BiFunction> value2, final Function3> value3, final Function4 filterFunction, final Function4 yieldingFunction) { if(!def1.monadZero().isPresent()) return Maybe.nothing(); MonadZero mZero = def1.monadZero().orElse(null); return Maybe.just(of(Comprehensions.of(mZero).forEach4(this.single,value1,value2,value3,filterFunction,yieldingFunction),def1)); } public Active forEach3(final Function> value1, final BiFunction> value2, final Function3 yieldingFunction) { return of(Comprehensions.of(def1.monad()).forEach3(this.single,value1,value2,yieldingFunction),def1); } public Maybe> forEach3(final Function> value1, final BiFunction> value2, final Function3 filterFunction, final Function3 yieldingFunction) { if(!def1.monadZero().isPresent()) return Maybe.nothing(); MonadZero mZero = def1.monadZero().orElse(null); return Maybe.just(of(Comprehensions.of(mZero).forEach3(this.single,value1,value2,filterFunction,yieldingFunction),def1)); } public Active forEach2(Function> value1, final BiFunction yieldingFunction) { return of(Comprehensions.of(def1.monad()).forEach2(this.single,value1,yieldingFunction),def1); } public Maybe> forEach2(Function> value1, final BiFunction filterFunction, final BiFunction yieldingFunction) { if(!def1.monadZero().isPresent()) return Maybe.nothing(); MonadZero mZero = def1.monadZero().orElse(null); return Maybe.just(of(Comprehensions.of(mZero).forEach2(this.single,value1,filterFunction,yieldingFunction),def1)); } public String show(){ return def1.show().show(single); } public String toString(){ return "Active["+single.toString()+"]"; } }