cyclops.arrow.Kleisli 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
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 super T, ? extends Higher> fn;
public static Kleisli of(Monad monad, Function super T, ? extends Higher> fn){
return new Kleisli(monad,fn);
}
public static Kleisli arrow(Monad monad, Function super T, ? extends R> 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 super R, ? extends R> local){
return kleisliK(monad, t->monad.map(r->local.apply(r),apply(t)));
}
public Kleisli map(Function super R, ? extends R1> mapper){
return kleisliK(monad,andThen(am->monad.map(mapper,am)));
}
public Kleisli flatMap(Function super R, ? extends Higher> 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 super R,? super R2,? extends B> fn){
return flatMapK(a -> o.map(b -> fn.apply(a,b)));
}
public Kleisli flatMapK(Function super R, ? extends Kleisli> 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 super R, Function super T,? extends Higher>> value2,
BiFunction super R, ? super R1, Function super T,? extends Higher>> value3,
Function3 super R, ? super R1, ? super R2, Function super T,? extends Higher>> value4,
Function4 super R, ? super R1, ? super R2, ? super R3, ? extends R4> 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 super R, Function super T,? extends Higher>> value2,
BiFunction super R, ? super R1, Function super T,? extends Higher>> value3,
Function3 super R, ? super R1, ? super R2, ? extends R4> 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 super R, Function super T,? extends Higher>> value2,
BiFunction super R, ? super R1, ? extends R4> 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 super R, ? extends Kleisli> value2,
BiFunction super R, ? super R1, ? extends Kleisli> value3,
Function3 super R, ? super R1, ? super R2, ? extends Kleisli> value4,
Function4 super R, ? super R1, ? super R2, ? super R3, ? extends R4> 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 super R, ? extends Kleisli> value2,
BiFunction super R, ? super R1, ? extends Kleisli> value3,
Function3 super R, ? super R1, ? super R2, ? extends R4> 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 super R, ? extends Kleisli> value2,
BiFunction super R, ? super R1, ? extends R4> 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 super T,? extends Higher> fn){
return of(monad,fn);
}
public static Kleisli lift(Monad monad, Function super T,? extends R> fn, W type){
return kleisliK(monad,fn.andThen(r->monad.unit(r)));
}
public static Function1> narrow(Function super T, ? extends Higher> 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);
}
}