Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
cyclops.control.Ior Maven / Gradle / Ivy
Go to download
Platform for Functional Reactive Programming with Java 8
package cyclops.control;
import com.oath.cyclops.hkt.Higher;
import com.oath.cyclops.hkt.Higher2;
import com.oath.cyclops.types.Filters;
import com.oath.cyclops.types.OrElseValue;
import com.oath.cyclops.types.Value;
import com.oath.cyclops.types.factory.Unit;
import com.oath.cyclops.types.foldable.To;
import com.oath.cyclops.types.functor.BiTransformable;
import com.oath.cyclops.types.functor.Transformable;
import com.oath.cyclops.types.reactive.ValueSubscriber;
import cyclops.function.*;
import com.oath.cyclops.hkt.DataWitness.ior;
import cyclops.reactive.ReactiveSeq;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import cyclops.data.tuple.Tuple;
import cyclops.data.tuple.Tuple2;
import org.reactivestreams.Publisher;
import java.util.Iterator;
import java.util.Optional;
import java.util.function.*;
/**
* Inclusive Or (can be one of Primary, Secondary or Both Primary and Secondary)
*
* An Either or Union type, but right biased. Primary and Secondary are used instead of Right & Left.
* 'Right' (or right type) biased disjunct union.
* No 'projections' are provided, swap() and secondaryXXXX alternative methods can be used instead.
*
*
* For exclusive or @see Either
*
* @author johnmcclean
*
* @param Left type
* @param Right type
*/
public interface Ior extends To>, Value,OrElseValue>,Unit, Transformable, Filters, BiTransformable ,Higher2 {
public static Higher, T> widen(Ior narrow) {
return narrow;
}
Ior recover(Supplier value);
Ior recover(RT value);
Ior recoverWith(Supplier> fn);
default int arity(){
return 2;
}
/**
* Static method useful as a method reference for fluent consumption of any value type stored in this Either
* (will capture the lowest common type)
*
*
* {@code
*
* myEither.to(Xor::consumeAny)
.accept(System.out::println);
* }
*
*
* @param either Xor to consume value for
* @return Consumer we can applyHKT to consume value
*/
static Consumer> consumeAny(Ior either){
return in->visitAny(in,either);
}
static Function,R> applyAny(Ior either){
return in->visitAny(either,in);
}
@Deprecated //use foldAny
static R visitAny(Ior either, Function fn){
return foldAny(either,fn);
}
static R foldAny(Ior either, Function fn){
return either.fold(fn, fn, (a, b)-> fn.apply(a));
}
static X visitAny(Consumer c,Ior either){
Function fn = x ->{
c.accept(x);
return x;
};
return visitAny(either,fn);
}
/**
* Construct an Ior that contains a single value extracted from the supplied reactive-streams Publisher
*
* {@code
* ReactiveSeq stream = ReactiveSeq.of(1,2,3);
Ior future = Ior.fromPublisher(stream);
//Ior[1]
*
* }
*
*
* @param pub Publisher to extract value from
* @return Ior populated from Publisher
*/
public static Ior fromPublisher(final Publisher pub) {
final ValueSubscriber sub = ValueSubscriber.subscriber();
pub.subscribe(sub);
return sub.toEither()
.toIor();
}
/**
* Construct an Ior that contains a single value extracted from the supplied Iterable
*
* {@code
* List list = Arrays.asList(1,2,3);
Ior future = Ior.fromPublisher(list);
//Ior[1]
*
* }
*
* @param iterable Iterable to extract value from
* @return Ior populated from Iterable
*/
public static Ior fromIterable(final Iterable iterable, T alt) {
final Iterator it = iterable.iterator();
return Ior.right(it.hasNext() ? it.next() : alt);
}
/**
* Create an instance of the right type. Most methods are biased to the right type,
* which means, for example, that the transform method operates on the right type but does nothing on left Iors
*
*
* {@code
* Ior.right(10).map(i->i+1);
* //Ior.right[11]
*
*
* }
*
*
*
* @param right To construct an Ior from
* @return Primary type instanceof Ior
*/
public static Ior right(final RT right) {
return new Primary<>(
right);
}
/**
* Create an instance of the left type. Most methods are biased to the right type,
* so you will need to use swap() or leftXXXX to manipulate the wrapped value
*
*
* {@code
* Ior.left(10).map(i->i+1);
* //Ior.left[10]
*
* Ior.left(10).swap().map(i->i+1);
* //Ior.right[11]
* }
*
*
*
* @param left to wrap
* @return Secondary instance of Ior
*/
public static Ior left(final LT left) {
return new Secondary<>(
left);
}
/**
* Create an Ior instance that contains both left and right types
*
*
* {@code
* Ior kv = Ior.both("hello",90);
* //Ior["hello",90]
* }
*
*
* @param left Secondary value
* @param right Primary value
* @return Ior that contains both the left and the right value
*/
public static Ior both(final ST left, final PT right) {
return new Both(
left, right);
}
default Ior forEach4(Function> value1,
BiFunction> value2,
Function3> value3,
Function4 yieldingFunction) {
return this.flatMap(in-> {
Ior a = value1.apply(in);
return a.flatMap(ina-> {
Ior b = value2.apply(in,ina);
return b.flatMap(inb-> {
Ior c= value3.apply(in,ina,inb);
return c.map(in2->yieldingFunction.apply(in,ina,inb,in2));
});
});
});
}
default Ior forEach3(Function> value1,
BiFunction> value2,
Function3 yieldingFunction) {
return this.flatMap(in-> {
Ior a = value1.apply(in);
return a.flatMap(ina-> {
Ior b = value2.apply(in,ina);
return b.map(in2->yieldingFunction.apply(in,ina, in2));
});
});
}
default Ior forEach2(Function> value1,
BiFunction yieldingFunction) {
return this.flatMap(in-> {
Ior b = value1.apply(in);
return b.map(in2->yieldingFunction.apply(in, in2));
});
}
/* (non-Javadoc)
* @see com.oath.cyclops.types.MonadicValue#unit(java.lang.Object)
*/
@Override
default Ior unit(final T unit) {
return Ior.right(unit);
}
/* (non-Javadoc)
* @see com.oath.cyclops.types.Filters#filter(java.util.function.Predicate)
*/
@Override
Option filter(Predicate test);
/* (non-Javadoc)
* @see com.oath.cyclops.types.Value#toLazyEither()
*/
Either toEither();
/**
* @return Convert to an Either, dropping the right type if this Ior contains both
*/
Either toEitherDropRight(); //drop PT
/* (non-Javadoc)
* @see com.oath.cyclops.types.Value#toLazyEither(java.lang.Object)
*/
@Override
default Either toEither(final ST2 secondary) {
return fold(s -> Either.left(secondary), p -> Either.right(p), (s, p) -> Either.right(p));
}
Ior mapLeft(Function fn);
@Override
Ior map(Function fn);
Ior peekLeft(Consumer action);
/* (non-Javadoc)
* @see com.oath.cyclops.types.functor.Transformable#peek(java.util.function.Consumer)
*/
@Override
Ior peek(Consumer action);
/**
* @return Ior with Primary and Secondary types and value swapped
*/
Ior swap();
default Ior coflatMap(final Function, R> mapper) {
return mapper.andThen(r -> unit(r))
.apply(this);
}
//cojoin
default Ior> nest() {
return this.map(t -> unit(t));
}
/**
* @return An zero Option if this Ior only has lazy the Secondary or Primary type. Or an Optional containing a Tuple2
* with both the Secondary and Primary types if they are both present.
*/
Option> both();
/* (non-Javadoc)
* @see com.oath.cyclops.types.functor.BiTransformable#bimap(java.util.function.Function, java.util.function.Function)
*/
@Override
Ior bimap(final Function fn1, final Function fn2);
/**
* Visitor pattern for this Ior.
* Execute the left function if this Ior contains an element of the left type only
* Execute the right function if this Ior contains an element of the right type only
* Execute the both function if this Ior contains an element of both type
*
*
* {@code
* Ior.right(10)
* .visit(left->"no", right->"yes",(sec,pri)->"oops!")
* //Ior["yes"]
Ior.left(90)
.visit(left->"no", right->"yes",(sec,pri)->"oops!")
//Ior["no"]
Ior.both(10, "eek")
.visit(left->"no", right->"yes",(sec,pri)->"oops!")
//Ior["oops!"]
*
*
* }
*
*
* @param secondary Function to execute if this is a Secondary Ior
* @param primary Function to execute if this is a Primary Ior
* @param both Function to execute if this Ior contains both types
* @return Result of executing the appropriate function
*/
R fold(final Function secondary, final Function primary,
final BiFunction both) ;
/* (non-Javadoc)
* @see java.util.function.Supplier#getValue()
*/
Option get();
/* (non-Javadoc)
* @see com.oath.cyclops.types.foldable.Convertable#isPresent()
*/
@Override
default boolean isPresent() {
return isRight() || isBoth();
}
Option getLeft();
public Ior flatMap(final Function> mapper);
/**
* Perform a flatMap operation on the Secondary type
*
* @param mapper Flattening transformation function
* @return Ior containing the value inside the result of the transformation function as the Secondary value, if the Secondary type was present
*/
Ior flatMapLeft(Function> mapper);
/**
* @return True if this is a right (only) Ior
*/
public boolean isRight();
/**
* @return True if this was a left (only) Ior
*/
public boolean isLeft();
/**
* @return True if this Ior has both left and right types
*/
public boolean isBoth();
/**
* Turn a toX of Iors into a single Ior with Lists of values.
* Primary and left types are swapped during this operation.
*
*
* {@code
* Ior just = Ior.right(10);
Ior none = Ior.left("none");
* Ior,Seq> iors =Ior.sequenceLeft(Seq.of(just,none,Ior.right(1)));
//Ior.right(Seq.of("none")))
*
* }
*
*
*
* @param iors Iors to sequence
* @return Ior sequenced and swapped
*/
public static Ior> sequenceLeft(final Iterable> iors) {
return sequence(ReactiveSeq.fromIterable(iors).filterNot(Ior::isRight).map(Ior::swap));
}
/**
* Accumulate the result of the Secondary types in the Collection of Iors provided using the supplied Reducer {@see cyclops2.Reducers}.
*
*
* {@code
* Ior just = Ior.right(10);
Ior none = Ior.left("none");
* Ior> iors = Ior.accumulateLeft(Seq.of(just,none,Ior.right(1)),Reducers.toPersistentSetX());
//Ior.right(PersistentSetX.of("none"))));
* }
*
* @param iors Collection of Iors to accumulate left values
* @param reducer Reducer to accumulate results
* @return Ior populated with the accumulate left operation
*/
public static Ior accumulateLeft(final Iterable> iors, final Reducer reducer) {
return sequenceLeft(iors).map(s -> s.foldMap(reducer));
}
/**
* Accumulate the results only from those Iors which have a Secondary type present, using the supplied mapping function to
* convert the data from each Ior 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
* Ior just = Ior.right(10);
Ior none = Ior.left("none");
* Ior iors = Ior.accumulateLeft(Seq.of(just,none,Ior.left("1")),i->""+i,Monoids.stringConcat);
//Ior.right("none1")
*
* }
*
*
*
*
* @param iors Collection of Iors to accumulate left values
* @param mapper Mapping function to be applied to the result of each Ior
* @param reducer Semigroup to combine values from each Ior
* @return Ior populated with the accumulate Secondary operation
*/
public static Ior accumulateLeft(final Iterable> iors, final Function mapper,
final Monoid reducer) {
return sequenceLeft(iors).map(s -> s.map(mapper)
.reduce(reducer));
}
/**
* Accumulate the results only from those Iors which have a Secondary type 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
*
* Ior just = Ior.right(10);
Ior none = Ior.left("none");
* Ior iors = Ior.accumulateLeft(Monoids.intSum,Seq.of(Ior.both(2, "boo!"),Ior.left(1)));
//Ior.right(3); 2+1
*
*
* }
*
*
*
* @param iors Collection of Iors to accumulate left values
* @param reducer Semigroup to combine values from each Ior
* @return populated with the accumulate Secondary operation
*/
public static Ior accumulateLeft(final Monoid reducer, final Iterable> iors) {
return sequenceLeft(iors).map(s -> s.reduce(reducer));
}
/**
* Turn a toX of Iors into a single Ior with Lists of values.
*
*
* {@code
*
* Ior just = Ior.right(10);
Ior none = Ior.left("none");
* Ior> iors =Ior.sequenceRight(Seq.of(just,none,Ior.right(1)));
//Ior.right(Seq.of(10,1)));
*
* }
*
*
*
* @param iors Iors to sequence
* @return Ior Sequenced
*/
public static Ior> sequenceRight(final Iterable> iors) {
return sequence(ReactiveSeq.fromIterable(iors).filterNot(Ior::isLeft));
}
public static Ior> sequence(ReactiveSeq> stream) {
Ior> identity = right(ReactiveSeq.empty());
BiFunction>,Ior,Ior>> combineToStream = (acc,next) ->acc.zip(next,(a,b)->a.append(b));
BinaryOperator>> combineStreams = (a,b)-> a.zip(b,(z1,z2)->z1.appendStream(z2));
return stream.reduce(identity,combineToStream,combineStreams);
}
public static Ior> traverse(Function fn,ReactiveSeq> stream) {
return sequence(stream.map(h->h.map(fn)));
}
/**
* Accumulate the result of the Primary types in the Collection of Iors provided using the supplied Reducer {@see cyclops2.Reducers}.
*
* {@code
* Ior just = Ior.right(10);
Ior none = Ior.left("none");
*
* Ior> iors =Ior.accumulateRight(Seq.of(just,none,Ior.right(1)),Reducers.toPersistentSetX());
//Ior.right(PersistentSetX.of(10,1))));
* }
*
* @param iors Collection of Iors to accumulate right values
* @param reducer Reducer to accumulate results
* @return Ior populated with the accumulate right operation
*/
public static Ior accumulateRight(final Iterable> iors, final Reducer reducer) {
return sequenceRight(iors).map(s -> s.foldMap(reducer));
}
/**
* Accumulate the results only from those Iors which have a Primary type present, using the supplied mapping function to
* convert the data from each Ior before reducing them using the supplied Semgigroup (a combining BiFunction/BinaryOperator that takes two
* input values of the same type and returns the combined result) {@see cyclops2.SemigroupK }.
*
*
* {@code
* Ior just = Ior.right(10);
Ior none = Ior.left("none");
* Ior iors = Ior.accumulateRight(Seq.of(just,none,Ior.right(1)),i->""+i,SemigroupK.stringConcat);
//Ior.right("101"));
* }
*
*
*
* @param iors Collection of Iors to accumulate right values
* @param mapper Mapping function to be applied to the result of each Ior
* @param reducer Reducer to accumulate results
* @return Ior populated with the accumulate right operation
*/
public static Ior accumulateRight(final Iterable> iors, final Function mapper,
final Semigroup reducer) {
return sequenceRight(iors).map(s -> s.map(mapper)
.reduce(reducer)
.get());
}
/**
* Accumulate the results only from those Iors which have a Primary type present, using the supplied Semgigroup (a combining BiFunction/BinaryOperator that takes two
* input values of the same type and returns the combined result) {@see cyclops2.SemigroupK }.
*
*
* {@code
* Ior just = Ior.right(10);
Ior none = Ior.left("none");
*
* Ior iors =Ior.accumulateRight(Seq.of(just,none,Ior.right(1)),SemigroupK.intSum);
//Ior.right(11);
*
* }
*
*
*
*
* @param iors Collection of Iors to accumulate right values
* @param reducer Reducer to accumulate results
* @return Ior populated with the accumulate right operation
*/
public static Ior accumulateRight(final Iterable> iors, final Semigroup reducer) {
return sequenceRight(iors).map(s -> s.reduce(reducer)
.get());
}
/* (non-Javadoc)
* @see com.oath.cyclops.lambda.monads.Filters#ofType(java.lang.Class)
*/
@Override
default Option ofType(final Class type) {
return (Option) Filters.super.ofType(type);
}
/* (non-Javadoc)
* @see com.oath.cyclops.lambda.monads.Filters#filterNot(java.util.function.Predicate)
*/
@Override
default Option filterNot(final Predicate fn) {
return (Option) Filters.super.filterNot(fn);
}
@Override
default Option notNull() {
return (Option) Filters.super.notNull();
}
/* (non-Javadoc)
* @see com.oath.cyclops.lambda.monads.BiTransformable#bipeek(java.util.function.Consumer, java.util.function.Consumer)
*/
@Override
default Ior bipeek(final Consumer c1, final Consumer c2) {
return (Ior) BiTransformable.super.bipeek(c1, c2);
}
default Ior zip(final Ior app, final BiFunction fn){
return flatMap(t->app.map(t2->fn.apply(t,t2)));
}
default Ior zip(final Either app, final BiFunction fn){
return flatMap(t->app.map(t2->fn.apply(t,t2)).toIor());
}
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@EqualsAndHashCode(of = { "value" })
public static class Primary implements Ior {
private final PT value;
@Override
public Either toEither() {
return Either.right(value);
}
@Override
public Either toEitherDropRight() {
return Either.right(value);
}
@Override
public Ior recover(Supplier value) {
return this;
}
@Override
public Ior recover(PT value) {
return this;
}
@Override
public Ior recoverWith(Supplier> fn) {
return this;
}
@Override
public Ior mapLeft(final Function fn) {
return (Ior) this;
}
@Override
public Ior map(final Function fn) {
return new Primary(
fn.apply(value));
}
@Override
public Ior peekLeft(final Consumer action) {
return this;
}
@Override
public R fold(final Function secondary, final Function primary,
final BiFunction both) {
return primary.apply(value);
}
@Override
public Ior peek(final Consumer action) {
action.accept(value);
return this;
}
@Override
public Option filter(final Predicate test) {
if (test.test(value))
return Option.some(value);
return Option.none();
}
@Override
public Ior bimap(final Function fn1, final Function fn2) {
return Ior.right(fn2.apply(value));
}
@Override
public Ior swap() {
return new Secondary(
value);
}
@Override
public Option get() {
return Option.some(value);
}
@Override
public Option getLeft() {
return Option.none();
}
@Override
public Ior flatMap(final Function> mapper) {
Ior x = mapper.apply(value);
return (Ior)x;
}
@Override
public Ior flatMapLeft(final Function> mapper) {
return (Ior) this;
}
@Override
public Ior bipeek(final Consumer stAction, final Consumer ptAction) {
ptAction.accept(value);
return this;
}
@Override
public Option> both() {
return Option.none();
}
@Override
public boolean isRight() {
return true;
}
@Override
public boolean isLeft() {
return false;
}
@Override
public boolean isBoth() {
return false;
}
@Override
public String toString() {
return mkString();
}
@Override
public String mkString() {
return "Ior.right[" + value + "]";
}
@Override
public R fold(Function present, Supplier absent) {
return present.apply(value);
}
}
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@EqualsAndHashCode(of = {"value"})
public static class Secondary implements Ior {
private final ST value;
@Override
public Ior recover(Supplier value) {
return Ior.both(this.value,value.get());
}
@Override
public Ior recover(PT value) {
return Ior.both(this.value,value);
}
@Override
public Ior recoverWith(Supplier> fn) {
return fn.get();
}
@Override
public boolean isLeft() {
return true;
}
@Override
public boolean isRight() {
return false;
}
@Override
public Either toEither() {
return Either.left(value);
}
@Override
public Either toEitherDropRight() {
return Either.left(value);
}
@Override
public Ior mapLeft(final Function fn) {
return new Secondary(
fn.apply(value));
}
@Override
public Ior map(final Function fn) {
return (Ior) this;
}
@Override
public Ior peekLeft(final Consumer action) {
return mapLeft((Function) FluentFunctions.expression(action));
}
@Override
public Option> both() {
return Option.none();
}
@Override
public Ior peek(final Consumer action) {
return this;
}
@Override
public Option filter(final Predicate test) {
return Option.none();
}
@Override
public Ior bimap(final Function fn1, final Function fn2) {
return Ior.left(fn1.apply(value));
}
@Override
public Ior swap() {
return new Primary(
value);
}
@Override
public Option get() {
return Option.none();
}
@Override
public Option getLeft() {
return Option.some(value);
}
@Override
public Ior flatMap(final Function> mapper) {
return (Ior) this;
}
@Override
public Ior flatMapLeft(final Function> mapper) {
return mapper.apply(value);
}
@Override
public Ior bipeek(final Consumer stAction, final Consumer ptAction) {
stAction.accept(value);
return this;
}
@Override
public R fold(final Function secondary, final Function primary,
final BiFunction both) {
return swap().fold(secondary, () -> null);
}
@Override
public boolean isBoth() {
return false;
}
@Override
public Maybe toMaybe() {
return Maybe.nothing();
}
@Override
public Optional toOptional() {
return Optional.empty();
}
@Override
public String toString() {
return mkString();
}
@Override
public String mkString() {
return "Ior.left[" + value + "]";
}
@Override
public R fold(Function present, Supplier absent) {
return absent.get();
}
}
@AllArgsConstructor(access = AccessLevel.PACKAGE)
@EqualsAndHashCode(of = {"left", "right"})
public static class Both implements Ior {
private final ST secondary;
private final PT primary;
private static Ior both(final ST secondary, final PT primary) {
return new Both(
secondary, primary);
}
@Override
public ReactiveSeq stream() {
return ReactiveSeq.of(primary);
}
@Override
public Ior recover(Supplier value) {
return this;
}
@Override
public Ior recover(PT value) {
return this;
}
@Override
public Ior recoverWith(Supplier> fn) {
return this;
}
@Override
public Iterator iterator() {
return stream().iterator();
}
@Override
public Either toEither() {
return Either.right(primary);
}
@Override
public Either toEitherDropRight() {
return Either.left(secondary);
}
@Override
public Ior mapLeft(final Function fn) {
return Both.both(fn.apply(secondary), primary);
}
@Override
public Ior map(final Function fn) {
return Both.both(secondary, fn.apply(primary));
}
@Override
public Ior peekLeft(final Consumer action) {
action.accept(secondary);
return this;
}
@Override
public Ior peek(final Consumer action) {
action.accept(primary);
return this;
}
@Override
public Option filter(final Predicate test) {
return Either.right(primary).filter(test);
}
@Override
public Ior swap() {
return Both.both(primary, secondary);
}
@Override
public R fold(final Function secondary, final Function primary,
final BiFunction both) {
return both.apply(this.secondary,this.primary);
}
@Override
public Option> both() {
return Option.some(Tuple.tuple(secondary, primary));
}
@Override
public Option get() {
return Option.of(primary);
}
@Override
public Option getLeft() {
return Option.of(secondary);
}
@Override
public Ior flatMap(final Function> mapper) {
Ior x = mapper.apply(primary);
return (Ior)x;
}
@Override
public Ior flatMapLeft(final Function> mapper) {
return mapper.apply(secondary);
}
@Override
public Ior bipeek(final Consumer actionA, final Consumer actionB) {
actionA.accept(secondary);
actionB.accept(primary);
return this;
}
@Override
public Ior bimap(final Function fn1, final Function fn2) {
return Both.both(fn1.apply(secondary), fn2.apply(primary));
}
@Override
public boolean isRight() {
return false;
}
@Override
public boolean isLeft() {
return false;
}
@Override
public boolean isBoth() {
return true;
}
@Override
public String toString() {
return mkString();
}
@Override
public String mkString() {
return "Ior.both[" + primary.toString() + ":" + secondary.toString() + "]";
}
@Override
public R fold(Function present, Supplier absent) {
return present.apply(primary);
}
}
public static Ior narrowK2(final Higher2 ior) {
return (Ior)ior;
}
public static Ior narrowK(final Higher,T> ior) {
return (Ior)ior;
}
}