cyclops.hkt.Active 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.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 super C,? extends Higher> 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 super Higher,? extends S> narrow,Function super S,? extends Higher> 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 super Higher,? 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 super Higher,? extends C> narrow, Function super C,? extends R> visitor){
return visitor.apply(narrow.apply(single));
}
public R fold(Function super Higher,? extends R> visitor){
return visitor.apply(single);
}
public R visitA(Function super Active,? 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 super T> 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 super T, ? extends R> fn) {
return of(def1.functor().map(fn, single), def1);
}
public Active mapWithIndex(BiFunction super T,Long,? extends R> 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 super T> pred){
return def1.foldable().anyMatch(pred,single);
}
public boolean allMatch(Predicate super T> 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 super T,? super Maybe,? extends R> f) {
return of(def1.traverse().zipWith(a.def1.foldable(),f,single,a.single),def1);
}
public Active zipWith(Foldable foldable,Higher a, BiFunction super T,? super Maybe,? 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 super T, ? extends C> fn) {
return Active.this.flatMap(fn.andThen(narrow));
}
public Active zip(C fb, BiFunction super T,? super R,? extends R2> 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 super T,? extends C> 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 super T,? super T2,? extends R> f) {
return of(def1.applicative().zip(single,fb,f),def1);
}
public Eval> lazyZip(Eval> lazy, BiFunction super T,? super T2,? extends R> fn) {
return lazy.map(e-> zip(e,fn));
}
public Eval> lazyZipA(Eval> lazy, BiFunction super T,? super T2,? extends R> fn) {
return lazy.map(e->zip(e.getSingle(),fn));
}
public Active peek(Consumer super T> fn) {
return of(def1.functor().peek(fn, single), def1);
}
public Function, Active> lift(final Function super T, ? extends R> 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 super T,? super T, ? extends R> 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 super T,? super T, ? super T,? extends R> 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 super T, ? extends Higher> fn) {
return of(def1.monad().flatMap(fn, single), def1);
}
public Active flatMapA(Function super T, ? extends Active> 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 super C, ? extends Higher>> 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 super T,? extends Higher>> fn){
return of(def1.monadRec().tailRec(initial,fn),def1);
}
public Active tailRecA(T initial,Function super T,? extends Active>> 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 super T, Option>> 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 super T,Long> fn, Function super T,R> 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 super T,? extends R> 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 super T,? extends Higher>>f) {
return def1.traverse()
.flatTraverse(applicative,def1.monad(),single,f);
}
public Higher> traverseA(Applicative applicative, Function super T, ? extends Higher> fn){
return traverseA(applicative,fn,this);
}
public static Higher> traverseA(Applicative applicative, Function super T, ? extends Higher> 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 super T,? extends Higher>> 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 extends U> type) {
return (Active)Filters.super.ofType(type);
}
@Override
public Active filterNot(Predicate super T> predicate) {
return (Active)Filters.super.filterNot(predicate);
}
@Override
public Active notNull() {
return (Active)Filters.super.notNull();
}
public Active