cyclops.companion.vavr.Lazys Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cyclops-vavr Show documentation
Show all versions of cyclops-vavr Show documentation
Converters and Comprehenders for Javaslang
The newest version!
package cyclops.companion.vavr;
import cyclops.monads.VavrWitness.*;
import cyclops.monads.VavrWitness.list;
import cyclops.monads.VavrWitness.stream;
import cyclops.monads.VavrWitness.tryType;
import io.vavr.collection.*;
import io.vavr.concurrent.Future;
import io.vavr.control.*;
import com.aol.cyclops.vavr.hkt.*;
import cyclops.companion.CompletableFutures;
import cyclops.companion.Optionals;
import cyclops.control.Eval;
import cyclops.control.Maybe;
import cyclops.control.Reader;
import cyclops.control.Xor;
import cyclops.conversion.vavr.FromCyclopsReact;
import cyclops.monads.*;
import com.aol.cyclops2.hkt.Higher;
import cyclops.function.Fn3;
import cyclops.function.Fn4;
import cyclops.function.Monoid;
import cyclops.monads.Witness.*;
import cyclops.stream.ReactiveSeq;
import cyclops.typeclasses.*;
import com.aol.cyclops.vavr.hkt.EitherKind;
import cyclops.conversion.vavr.ToCyclopsReact;
import com.aol.cyclops.vavr.hkt.LazyKind;
import com.aol.cyclops2.data.collections.extensions.CollectionX;
import com.aol.cyclops2.types.Value;
import cyclops.collections.mutable.ListX;
import cyclops.function.Reducer;
import cyclops.monads.transformers.EvalT;
import cyclops.typeclasses.comonad.Comonad;
import cyclops.typeclasses.foldable.Foldable;
import cyclops.typeclasses.foldable.Unfoldable;
import cyclops.typeclasses.functor.Functor;
import cyclops.typeclasses.instances.General;
import cyclops.typeclasses.monad.*;
import io.vavr.Lazy;
import io.vavr.control.Either;
import lombok.experimental.UtilityClass;
import org.reactivestreams.Publisher;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import static com.aol.cyclops.vavr.hkt.LazyKind.widen;
public class Lazys {
public static Coproduct coproduct(Lazy type, InstanceDefinitions def1){
return Coproduct.of(Xor.primary(widen(type)),def1, Instances.definitions());
}
public static Coproduct coproduct(Supplier type, InstanceDefinitions def1){
return coproduct(Lazy.of(type),def1);
}
/**
* Lifts a vavr Lazy into a cyclops LazyT monad transformer (involves an observables conversion to
* cyclops Lazy types)
*
*/
public static > EvalT liftM(Lazy opt, W witness) {
return EvalT.of(witness.adapter().unit(ToCyclopsReact.eval(opt)));
}
/**
* Perform a For Comprehension over a Lazy, accepting 3 generating function.
* This results in a four level nested internal iteration over the provided Lazys.
*
*
* {@code
*
* import static com.aol.cyclops2.reactor.Lazys.forEach4;
*
forEach4(Lazy.just(1),
a-> Lazy.just(a+1),
(a,b) -> Lazy.just(a+b),
a (a,b,c) -> Lazy.just(a+b+c),
Tuple::tuple)
*
* }
*
*
* @param value1 top level Lazy
* @param value2 Nested Lazy
* @param value3 Nested Lazy
* @param value4 Nested Lazy
* @param yieldingFunction Generates a result per combination
* @return Lazy with a combined value generated by the yielding function
*/
public static Lazy forEach4(Lazy extends T1> value1,
Function super T1, ? extends Lazy> value2,
BiFunction super T1, ? super R1, ? extends Lazy> value3,
Fn3 super T1, ? super R1, ? super R2, ? extends Lazy> value4,
Fn4 super T1, ? super R1, ? super R2, ? super R3, ? extends R> yieldingFunction) {
Eval res = ToCyclopsReact.eval(value1).flatMap(in -> {
Lazy a = value2.apply(in);
return ToCyclopsReact.eval(a).flatMap(ina -> {
Lazy b = value3.apply(in, ina);
return ToCyclopsReact.eval(b).flatMap(inb -> {
Lazy c = value4.apply(in, ina, inb);
return ToCyclopsReact.eval(c).map(in2 -> yieldingFunction.apply(in, ina, inb, in2));
});
});
});
return FromCyclopsReact.eval(res);
}
/**
* Perform a For Comprehension over a Lazy, accepting 2 generating function.
* This results in a three level nested internal iteration over the provided Lazys.
*
*
* {@code
*
* import static com.aol.cyclops2.reactor.Lazys.forEach3;
*
forEach3(Lazy.just(1),
a-> Lazy.just(a+1),
(a,b) -> Lazy.just(a+b),
Tuple::tuple)
*
* }
*
*
* @param value1 top level Lazy
* @param value2 Nested Lazy
* @param value3 Nested Lazy
* @param yieldingFunction Generates a result per combination
* @return Lazy with a combined value generated by the yielding function
*/
public static Lazy forEach3(Lazy extends T1> value1,
Function super T1, ? extends Lazy> value2,
BiFunction super T1, ? super R1, ? extends Lazy> value3,
Fn3 super T1, ? super R1, ? super R2, ? extends R> yieldingFunction) {
Eval extends R> res = ToCyclopsReact.eval(value1).flatMap(in -> {
Lazy a = value2.apply(in);
return ToCyclopsReact.eval(a).flatMap(ina -> {
Lazy b = value3.apply(in, ina);
return ToCyclopsReact.eval(b).map(in2 -> yieldingFunction.apply(in, ina, in2));
});
});
return FromCyclopsReact.eval(Eval.narrow(res));
}
/**
* Perform a For Comprehension over a Lazy, accepting a generating function.
* This results in a two level nested internal iteration over the provided Lazys.
*
*
* {@code
*
* import static com.aol.cyclops2.reactor.Lazys.forEach;
*
forEach(Lazy.just(1),
a-> Lazy.just(a+1),
Tuple::tuple)
*
* }
*
*
* @param value1 top level Lazy
* @param value2 Nested Lazy
* @param yieldingFunction Generates a result per combination
* @return Lazy with a combined value generated by the yielding function
*/
public static Lazy forEach2(Lazy extends T> value1, Function super T, Lazy> value2,
BiFunction super T, ? super R1, ? extends R> yieldingFunction) {
Eval extends R> res = ToCyclopsReact.eval(value1).flatMap(in -> {
Lazy a = value2.apply(in);
return ToCyclopsReact.eval(a).map(in2 -> yieldingFunction.apply(in, in2));
});
return FromCyclopsReact.eval(Eval.narrow(res));
}
/**
* Sequence operation, take a Collection of Lazys and turn it into a Lazy with a Collection
* By constrast with {@link Lazys#sequencePresent(CollectionX)}, if any Lazys are empty the result
* is an empty Lazy
*
*
* {@code
*
* Lazy just = Lazy.of(10);
Lazy none = Lazy.empty();
*
* Lazy> opts = Lazys.sequence(ListX.of(just, none, Lazy.of(1)));
//Lazy.empty();
*
* }
*
*
*
* @param opts Maybes to Sequence
* @return Maybe with a List of values
*/
public static Lazy> sequence(final CollectionX> opts) {
return sequence(opts.stream()).map(s -> s.toListX());
}
/**
* Sequence operation, take a Collection of Lazys and turn it into a Lazy with a Collection
* Only successes are retained. By constrast with {@link Lazys#sequence(CollectionX)} Lazy#empty types are
* tolerated and ignored.
*
*
* {@code
* Lazy just = Lazy.of(10);
Lazy none = Lazy.empty();
*
* Lazy> maybes = Lazys.sequencePresent(ListX.of(just, none, Lazy.of(1)));
//Lazy.of(ListX.of(10, 1));
* }
*
*
* @param opts Lazys to Sequence
* @return Lazy with a List of values
*/
public static Lazy> sequencePresent(final CollectionX> opts) {
return sequence(opts.stream().filter(Lazy::isEvaluated)).map(s->s.toListX());
}
/**
* Sequence operation, take a Collection of Lazys and turn it into a Lazy with a Collection
* By constrast with {@link Lazys#sequencePresent(CollectionX)} if any Lazy types are empty
* the return type will be an empty Lazy
*
*
* {@code
*
* Lazy just = Lazy.of(10);
Lazy none = Lazy.empty();
*
* Lazy> maybes = Lazys.sequence(ListX.of(just, none, Lazy.of(1)));
//Lazy.empty();
*
* }
*
*
*
* @param opts Maybes to Sequence
* @return Lazy with a List of values
*/
public static Lazy> sequence(final java.util.stream.Stream> opts) {
return FromCyclopsReact.eval(AnyM.sequence(opts.map(ToCyclopsReact::eval).map(AnyM::fromEval), Witness.eval.INSTANCE)
.map(ReactiveSeq::fromStream)
.to(Witness::eval));
}
/**
* Accummulating operation using the supplied Reducer (@see cyclops2.Reducers). A typical use case is to accumulate into a Persistent Collection type.
* Accumulates the present results, ignores empty Lazys.
*
*
* {@code
* Lazy just = Lazy.of(10);
Lazy none = Lazy.empty();
* Lazy> opts = Lazy.accumulateJust(ListX.of(just, none, Lazy.of(1)), Reducers.toPersistentSetX());
//Lazy.of(PersistentSetX.of(10, 1)));
*
* }
*
*
* @param futureals Lazys to accumulate
* @param reducer Reducer to accumulate values with
* @return Lazy with reduced value
*/
public static Lazy accumulatePresent(final CollectionX> futureals, final Reducer reducer) {
return sequencePresent(futureals).map(s -> s.mapReduce(reducer));
}
/**
* Accumulate the results only from those Lazys which have a value present, using the supplied mapping function to
* convert the data from each Lazy before reducing them using the supplied Monoid (a combining BiFunction/BinaryOperator and identity element that takes two
* input values of the same type and returns the combined result) {@see cyclops2.Monoids }.
*
*
* {@code
* Lazy just = Lazy.of(10);
Lazy none = Lazy.empty();
* Lazy opts = Lazy.accumulateJust(ListX.of(just, none, Lazy.of(1)), i -> "" + i,
Monoids.stringConcat);
//Lazy.of("101")
*
* }
*
*
* @param futureals Lazys to accumulate
* @param mapper Mapping function to be applied to the result of each Lazy
* @param reducer Monoid to combine values from each Lazy
* @return Lazy with reduced value
*/
public static Lazy accumulatePresent(final CollectionX> futureals, final Function super T, R> mapper,
final Monoid reducer) {
return sequencePresent(futureals).map(s -> s.map(mapper)
.reduce(reducer));
}
/**
* Accumulate the results only from those Lazys which have a value present, using the
* supplied Monoid (a combining BiFunction/BinaryOperator and identity element that takes two
* input values of the same type and returns the combined result) {@see cyclops2.Monoids }.
*
*
* {@code
* Lazy just = Lazy.of(10);
Lazy none = Lazy.empty();
* Lazy opts = Lazy.accumulateJust(Monoids.stringConcat,ListX.of(just, none, Lazy.of(1)),
);
//Lazy.of("101")
*
* }
*
*
* @param futureals Lazys to accumulate
* @param reducer Monoid to combine values from each Lazy
* @return Lazy with reduced value
*/
public static Lazy accumulatePresent(final Monoid reducer, final CollectionX> futureals) {
return sequencePresent(futureals).map(s -> s
.reduce(reducer));
}
/**
* Combine an Lazy with the provided value using the supplied BiFunction
*
*
* {@code
* Lazys.combine(Lazy.of(10),Maybe.just(20), this::add)
* //Lazy[30]
*
* private int add(int a, int b) {
return a + b;
}
*
* }
*
* @param f Lazy to combine with a value
* @param v Value to combine
* @param fn Combining function
* @return Lazy combined with supplied value
*/
public static Lazy combine(final Lazy extends T1> f, final Value extends T2> v,
final BiFunction super T1, ? super T2, ? extends R> fn) {
return narrow(FromCyclopsReact.eval(ToCyclopsReact.eval(f)
.combine(v, fn)));
}
/**
* Combine an Lazy with the provided Lazy using the supplied BiFunction
*
*
* {@code
* Lazys.combine(Lazy.of(10),Lazy.of(20), this::add)
* //Lazy[30]
*
* private int add(int a, int b) {
return a + b;
}
*
* }
*
*
* @param f Lazy to combine with a value
* @param v Lazy to combine
* @param fn Combining function
* @return Lazy combined with supplied value, or empty Lazy if no value present
*/
public static Lazy combine(final Lazy extends T1> f, final Lazy extends T2> v,
final BiFunction super T1, ? super T2, ? extends R> fn) {
return combine(f,ToCyclopsReact.eval(v),fn);
}
/**
* Combine an Lazy with the provided Iterable (selecting one element if present) using the supplied BiFunction
*
* {@code
* Lazys.zip(Lazy.of(10),Arrays.asList(20), this::add)
* //Lazy[30]
*
* private int add(int a, int b) {
return a + b;
}
*
* }
*
* @param f Lazy to combine with first element in Iterable (if present)
* @param v Iterable to combine
* @param fn Combining function
* @return Lazy combined with supplied Iterable, or empty Lazy if no value present
*/
public static Lazy zip(final Lazy extends T1> f, final Iterable extends T2> v,
final BiFunction super T1, ? super T2, ? extends R> fn) {
return narrow(FromCyclopsReact.eval(ToCyclopsReact.eval(f)
.zip(v, fn)));
}
/**
* Combine an Lazy with the provided Publisher (selecting one element if present) using the supplied BiFunction
*
* {@code
* Lazys.zip(Flux.just(10),Lazy.of(10), this::add)
* //Lazy[30]
*
* private int add(int a, int b) {
return a + b;
}
*
* }
*
*
* @param p Publisher to combine
* @param f Lazy to combine with
* @param fn Combining function
* @return Lazy combined with supplied Publisher, or empty Lazy if no value present
*/
public static Lazy zip(final Publisher extends T2> p, final Lazy extends T1> f,
final BiFunction super T1, ? super T2, ? extends R> fn) {
return narrow(FromCyclopsReact.eval(ToCyclopsReact.eval(f)
.zipP(p, fn)));
}
/**
* Narrow covariant type parameter
*
* @param futureal Lazy with covariant type parameter
* @return Narrowed Lazy
*/
public static Lazy narrow(final Lazy extends T> futureal) {
return (Lazy) futureal;
}
public static Active allTypeclasses(Lazy lazy){
return Active.of(widen(lazy), Lazys.Instances.definitions());
}
public static Nested mapM(Lazy lazy, Function super T,? extends Higher> fn, InstanceDefinitions defs){
Lazy> e = lazy.map(fn);
LazyKind> lk = widen(e);
return Nested.of(lk, Lazys.Instances.definitions(), defs);
}
@UtilityClass
public static class Instances {
public static InstanceDefinitions definitions() {
return new InstanceDefinitions() {
@Override
public Functor functor() {
return Instances.functor();
}
@Override
public Pure unit() {
return Instances.unit();
}
@Override
public Applicative applicative() {
return Instances.applicative();
}
@Override
public Monad monad() {
return Instances.monad();
}
@Override
public Maybe> monadZero() {
return Maybe.just(Instances.monadZero());
}
@Override
public Maybe> monadPlus() {
return Maybe.just(Instances.monadPlus());
}
@Override
public Maybe> monadPlus(Monoid> m) {
return Maybe.just(Instances.monadPlus(m));
}
@Override
public Maybe> traverse() {
return null;
}
@Override
public Maybe> foldable() {
return Maybe.just(Instances.foldable());
}
@Override
public Maybe> comonad() {
return Maybe.just(Instances.comonad());
}
@Override
public Maybe> unfoldable() {
return Maybe.none();
}
};
};
/**
*
* Transform a lazy, mulitplying every element by 2
*
*
* {@code
* LazyKind lazy = Instances.functor().map(i->i*2, LazyKind.widen(Lazy.of(()->1));
*
* //[2]
*
*
* }
*
*
* An example fluent api working with Lazys
*
* {@code
* LazyKind lazy = Lazys.unit()
.unit("hello")
.then(h->Lazys.functor().map((String v) ->v.length(), h))
.convert(LazyKind::narrowK);
*
* }
*
*
*
* @return A functor for Lazys
*/
public static Functor functor(){
BiFunction,Function super T, ? extends R>,LazyKind> map = Instances::map;
return General.functor(map);
}
/**
*
* {@code
* LazyKind lazy = Lazys.unit()
.unit("hello")
.convert(LazyKind::narrowK);
//Lazy.just("hello"))
*
* }
*
*
*
* @return A factory for Lazys
*/
public static Pure unit(){
return General.unit(Instances::of);
}
/**
*
*
* {@code
* import static com.aol.cyclops.hkt.jdk.LazyKind.widen;
* import static com.aol.cyclops.util.function.Lambda.l1;
* import static java.util.Lazy.just;
*
Lazys.zippingApplicative()
.ap(widen(asLazy(l1(this::multiplyByTwo))),widen(asLazy(1,2,3)));
*
* //[2,4,6]
* }
*
*
*
* Example fluent API
*
* {@code
* LazyKind> lazyFn =Lazys.unit()
* .unit(Lambda.l1((Integer i) ->i*2))
* .convert(LazyKind::narrowK);
LazyKind lazy = Lazys.unit()
.unit("hello")
.then(h->Lazys.functor().map((String v) ->v.length(), h))
.then(h->Lazys.applicative().ap(lazyFn, h))
.convert(LazyKind::narrowK);
//Lazy.just("hello".length()*2))
*
* }
*
*
*
* @return A zipper for Lazys
*/
public static Applicative applicative(){
BiFunction>,LazyKind,LazyKind> ap = Instances::ap;
return General.applicative(functor(), unit(), ap);
}
/**
*
*
* {@code
* import static com.aol.cyclops.hkt.jdk.LazyKind.widen;
* LazyKind lazy = Lazys.monad()
.flatMap(i->widen(LazyX.range(0,i)), widen(Lazy.just(1,2,3)))
.convert(LazyKind::narrowK);
* }
*
*
* Example fluent API
*
* {@code
* LazyKind lazy = Lazys.unit()
.unit("hello")
.then(h->Lazys.monad().flatMap((String v) ->Lazys.unit().unit(v.length()), h))
.convert(LazyKind::narrowK);
//Lazy.just("hello".length())
*
* }
*
*
* @return Type class with monad functions for Lazys
*/
public static Monad monad(){
BiFunction,Function super T, ? extends Higher>,Higher> flatMap = Instances::flatMap;
return General.monad(applicative(), flatMap);
}
/**
*
*
* {@code
* LazyKind lazy = Lazys.unit()
.unit("hello")
.then(h->Lazys.monadZero().filter((String t)->t.startsWith("he"), h))
.convert(LazyKind::narrowK);
//Lazy.just("hello"));
*
* }
*
*
*
* @return A filterable monad (with default value)
*/
public static MonadZero monadZero(){
return General.monadZero(monad(), LazyKind.of(()->null));
}
/**
*
* {@code
* LazyKind lazy = Lazys.monadPlus()
.plus(LazyKind.widen(Lazy.just()), LazyKind.widen(Lazy.just(10)))
.convert(LazyKind::narrowK);
//Lazy.just(10))
*
* }
*
* @return Type class for combining Lazys by concatenation
*/
public static MonadPlus monadPlus(){
Monoid> m = Monoid.of( LazyKind.of(()->null),
(a,b)-> a.get()==null? b: a);
Monoid> m2= (Monoid)m;
return General.monadPlus(monadZero(),m2);
}
/**
*
*
* {@code
* Monoid> m = Monoid.of(LazyKind.widen(Lazy.just()), (a,b)->a.isEmpty() ? b : a);
LazyKind lazy = Lazys.monadPlus(m)
.plus(LazyKind.widen(Lazy.just(5)), LazyKind.widen(Lazy.just(10)))
.convert(LazyKind::narrowK);
//Lazy[5]
*
* }
*
*
* @param m Monoid to use for combining Lazys
* @return Type class for combining Lazys
*/
public static MonadPlus monadPlus(Monoid> m){
Monoid> m2= (Monoid)m;
return General.monadPlus(monadZero(),m2);
}
public static MonadPlus monadPlusK(Monoid> m){
return monadPlus((Monoid)m);
}
/**
* @return Type class for traversables with traverse / sequence operations
*/
public static Traverse traverse(){
return General.traverseByTraverse(applicative(), Instances::traverseA);
}
/**
*
*
* {@code
* int sum = Lazys.foldable()
.foldLeft(0, (a,b)->a+b, LazyKind.widen(Lazy.just(1)));
//1
*
* }
*
*
*
* @return Type class for folding / reduction operations
*/
public static Foldable foldable(){
BiFunction,Higher,T> foldRightFn = (m, l)-> LazyKind.narrow(l).getOrElse(m.zero());
BiFunction,Higher,T> foldLeftFn = (m, l)-> LazyKind.narrow(l).getOrElse(m.zero());
return General.foldable(foldRightFn, foldLeftFn);
}
public static Comonad comonad(){
Function super Higher, ? extends T> extractFn = maybe -> maybe.convert(LazyKind::narrow).get();
return General.comonad(functor(), unit(), extractFn);
}
private LazyKind of(T value){
return widen(Lazy.of(()->value));
}
private static LazyKind ap(LazyKind> lt, LazyKind lazy){
return widen(FromCyclopsReact.lazy(ToCyclopsReact.eval(lt.narrow()).combine(ToCyclopsReact.eval(lazy.narrow()), (a, b)->a.apply(b))));
}
private static Higher flatMap(Higher lt, Function super T, ? extends Higher> fn){
return widen(LazyKind.narrowEval(lt).flatMap(fn.andThen(LazyKind::narrowEval)));
}
private static LazyKind map(LazyKind lt, Function super T, ? extends R> fn){
return widen(LazyKind.narrow(lt).map(fn));
}
private static Higher> traverseA(Applicative applicative, Function super T, ? extends Higher> fn,
Higher ds){
Lazy eval = LazyKind.narrow(ds);
Higher ds2 = fn.apply(eval.get());
return applicative.map(v-> LazyKind.of(()->v), ds2);
}
}
public static interface LazyNested{
public static Nested option(Lazy