fj.data.optic.POptional Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of functionaljava Show documentation
Show all versions of functionaljava Show documentation
Functional Java is an open source library that supports closures for the Java programming language
package fj.data.optic;
import fj.F;
import fj.Function;
import fj.Monoid;
import fj.P;
import fj.P1;
import fj.P2;
import fj.Semigroup;
import fj.control.Trampoline;
import fj.control.parallel.Promise;
import fj.control.parallel.Strategy;
import fj.data.Either;
import fj.data.IO;
import fj.data.IOFunctions;
import fj.data.List;
import fj.data.Option;
import fj.data.Stream;
import fj.data.Validation;
import fj.data.vector.V2;
/**
* A {@link POptional} can be seen as a pair of functions: - `getOrModify: S => T \/ A` - `set : (B, S) => T`
*
* A {@link POptional} could also be defined as a weaker {@link PLens} and weaker {@link PPrism}
*
* {@link POptional} stands for Polymorphic Optional as it set and modify methods change a type `A` to `B` and `S` to `T`.
* {@link Optional} is a {@link POptional} restricted to monomoprhic updates: {{{ type Optional[S, A] = POptional[S, S, A, A]
* }}}
*
* @param the source of a {@link POptional}
* @param the modified source of a {@link POptional}
* @param the target of a {@link POptional}
* @param the modified target of a {@link POptional}
*/
public abstract class POptional {
POptional() {
super();
}
/** get the target of a {@link POptional} or modify the source in case there is no target */
public abstract Either getOrModify(S s);
/** get the modified source of a {@link POptional} */
public abstract F set(final B b);
/** get the target of a {@link POptional} or nothing if there is no target */
public abstract Option getOption(final S s);
/**
* modify polymorphically the target of a {@link POptional} with an Applicative function
*/
public abstract F> modifyFunctionF(final F> f);
/**
* modify polymorphically the target of a {@link POptional} with an Applicative function
*/
public abstract F> modifyEitherF(final F> f);
/**
* modify polymorphically the target of a {@link POptional} with an Applicative function
*/
public abstract F> modifyIOF(F> f);
/**
* modify polymorphically the target of a {@link POptional} with an Applicative function
*/
public abstract F> modifyTrampolineF(F> f);
/**
* modify polymorphically the target of a {@link POptional} with an Applicative function
*/
public abstract F> modifyPromiseF(F> f);
/**
* modify polymorphically the target of a {@link POptional} with an Applicative function
*/
public abstract F> modifyListF(F> f);
/**
* modify polymorphically the target of a {@link POptional} with an Applicative function
*/
public abstract F> modifyOptionF(F> f);
/**
* modify polymorphically the target of a {@link POptional} with an Applicative function
*/
public abstract F> modifyStreamF(F> f);
/**
* modify polymorphically the target of a {@link POptional} with an Applicative function
*/
public abstract F> modifyP1F(F> f);
/**
* modify polymorphically the target of a {@link POptional} with an Applicative function
*/
public abstract F> modifyValidationF(F> f);
/**
* modify polymorphically the target of a {@link POptional} with an Applicative function
*/
public abstract F> modifyV2F(F> f);
/** modify polymorphically the target of a {@link POptional} with a function */
public abstract F modify(final F f);
/**
* modify polymorphically the target of a {@link POptional} with a function. return empty if the {@link POptional} is not
* matching
*/
public final F> modifyOption(final F f) {
return s -> getOption(s).map(Function.constant(modify(f).f(s)));
}
/** set polymorphically the target of a {@link POptional} with a value. return empty if the {@link POptional} is not matching */
public final F> setOption(final B b) {
return modifyOption(Function.constant(b));
}
/** check if a {@link POptional} has a target */
public final boolean isMatching(final S s) {
return getOption(s).isSome();
}
/** join two {@link POptional} with the same target */
public final POptional, Either, A, B> sum(final POptional other) {
return pOptional(
e -> e.either(s -> getOrModify(s).left().map(Either.left_()), s1 -> other.getOrModify(s1).left().map(Either.right_())),
b -> e -> e.bimap(set(b), other.set(b)));
}
public POptional, P2, P2, P2> first() {
return pOptional(
sc -> getOrModify(sc._1()).bimap(t -> P.p(t, sc._2()), a -> P.p(a, sc._2())),
bc -> s_ -> P.p(set(bc._1()).f(s_._1()), bc._2()));
}
public POptional, P2, P2, P2> second() {
return pOptional(
cs -> getOrModify(cs._2()).bimap(t -> P.p(cs._1(), t), a -> P.p(cs._1(), a)),
cb -> _s -> P.p(cb._1(), set(cb._2()).f(_s._2())));
}
/***************************************************************/
/** Compose methods between a {@link POptional} and another Optics */
/***************************************************************/
/** compose a {@link POptional} with a {@link Fold} */
public final Fold composeFold(final Fold other) {
return asFold().composeFold(other);
}
/** compose a {@link POptional} with a {@link Getter} */
public final Fold composeGetter(final Getter other) {
return asFold().composeGetter(other);
}
/** compose a {@link POptional} with a {@link PSetter} */
public final PSetter composeSetter(final PSetter other) {
return asSetter().composeSetter(other);
}
/** compose a {@link POptional} with a {@link PTraversal} */
public final PTraversal composeTraversal(final PTraversal other) {
return asTraversal().composeTraversal(other);
}
/** compose a {@link POptional} with a {@link POptional} */
public final POptional composeOptional(final POptional other) {
final POptional self = this;
return new POptional() {
@Override
public Either getOrModify(final S s) {
return self.getOrModify(s).right()
.bind(a -> other.getOrModify(a).bimap(b -> POptional.this.set(b).f(s), Function.identity()));
}
@Override
public F set(final D d) {
return self.modify(other.set(d));
}
@Override
public Option getOption(final S s) {
return self.getOption(s).bind(other::getOption);
}
@Override
public F> modifyFunctionF(final F> f) {
return self.modifyFunctionF(other.modifyFunctionF(f));
}
@Override
public F> modifyEitherF(final F> f) {
return self.modifyEitherF(other.modifyEitherF(f));
}
@Override
public F> modifyIOF(final F> f) {
return self.modifyIOF(other.modifyIOF(f));
}
@Override
public F> modifyTrampolineF(final F> f) {
return self.modifyTrampolineF(other.modifyTrampolineF(f));
}
@Override
public F> modifyPromiseF(final F> f) {
return self.modifyPromiseF(other.modifyPromiseF(f));
}
@Override
public F> modifyListF(final F> f) {
return self.modifyListF(other.modifyListF(f));
}
@Override
public F> modifyOptionF(final F> f) {
return self.modifyOptionF(other.modifyOptionF(f));
}
@Override
public F> modifyStreamF(final F> f) {
return self.modifyStreamF(other.modifyStreamF(f));
}
@Override
public F> modifyP1F(final F> f) {
return self.modifyP1F(other.modifyP1F(f));
}
@Override
public F> modifyValidationF(final F> f) {
return self.modifyValidationF(other.modifyValidationF(f));
}
@Override
public F> modifyV2F(final F> f) {
return self.modifyV2F(other.modifyV2F(f));
}
@Override
public F modify(final F f) {
return self.modify(other.modify(f));
}
};
}
/** compose a {@link POptional} with a {@link PPrism} */
public final POptional composePrism(final PPrism other) {
return composeOptional(other.asOptional());
}
/** compose a {@link POptional} with a {@link PLens} */
public final POptional composeLens(final PLens other) {
return composeOptional(other.asOptional());
}
/** compose a {@link POptional} with a {@link PIso} */
public final POptional composeIso(final PIso other) {
return composeOptional(other.asOptional());
}
/*********************************************************************/
/** Transformation methods to view a {@link POptional} as another Optics */
/*********************************************************************/
/** view a {@link POptional} as a {@link Fold} */
public final Fold asFold() {
return new Fold() {
@Override
public F foldMap(final Monoid m, final F f) {
return s -> POptional.this.getOption(s).map(f).orSome(m.zero());
}
};
}
/** view a {@link POptional} as a {@link PSetter} */
public PSetter asSetter() {
return new PSetter() {
@Override
public F modify(final F f) {
return POptional.this.modify(f);
}
@Override
public F set(final B b) {
return POptional.this.set(b);
}
};
}
/** view a {@link POptional} as a {@link PTraversal} */
public PTraversal asTraversal() {
final POptional self = this;
return new PTraversal() {
@Override
public F> modifyFunctionF(final F> f) {
return self.modifyFunctionF(f);
}
@Override
public F> modifyEitherF(final F> f) {
return self.modifyEitherF(f);
}
@Override
public F> modifyIOF(final F> f) {
return self.modifyIOF(f);
}
@Override
public F> modifyTrampolineF(final F> f) {
return self.modifyTrampolineF(f);
}
@Override
public F> modifyPromiseF(final F> f) {
return self.modifyPromiseF(f);
}
@Override
public F> modifyListF(final F> f) {
return self.modifyListF(f);
}
@Override
public F> modifyOptionF(final F> f) {
return self.modifyOptionF(f);
}
@Override
public F> modifyStreamF(final F> f) {
return self.modifyStreamF(f);
}
@Override
public F> modifyP1F(final F> f) {
return self.modifyP1F(f);
}
@Override
public F> modifyValidationF(Semigroup s, final F> f) {
return self.modifyValidationF(f);
}
@Override
public F> modifyV2F(final F> f) {
return self.modifyV2F(f);
}
@Override
public F foldMap(final Monoid monoid, final F f) {
return s -> self.getOption(s).map(f).orSome(monoid.zero());
}
};
}
public static POptional pId() {
return PIso. pId().asOptional();
}
/** create a {@link POptional} using the canonical functions: getOrModify and set */
public static POptional pOptional(final F> getOrModify, final F> set) {
return new POptional() {
@Override
public Either getOrModify(final S s) {
return getOrModify.f(s);
}
@Override
public F set(final B b) {
return set.f(b);
}
@Override
public Option getOption(final S s) {
return getOrModify.f(s).right().toOption();
}
@Override
public F> modifyFunctionF(final F> f) {
return s -> getOrModify.f(s).either(
Function.constant(),
a -> Function.compose(b -> set.f(b).f(s), f.f(a))
);
}
@Override
public F> modifyEitherF(final F> f) {
return s -> getOrModify.f(s).either(
Either.right_(),
t -> f.f(t).right().map(b -> set.f(b).f(s))
);
}
@Override
public F> modifyIOF(final F> f) {
return s -> getOrModify.f(s).either(
IOFunctions::unit,
t -> IOFunctions.map(f.f(t), b -> set.f(b).f(s))
);
}
@Override
public F> modifyTrampolineF(final F> f) {
return s -> getOrModify.f(s).either(
Trampoline.pure(),
t -> f.f(t).map(b -> set.f(b).f(s))
);
}
@Override
public F> modifyPromiseF(final F> f) {
return s -> getOrModify.f(s).either(
t -> Promise.promise(Strategy.idStrategy(), P.p(t)),
t -> f.f(t).fmap(b -> set.f(b).f(s))
);
}
@Override
public F> modifyListF(final F> f) {
return s -> getOrModify.f(s).either(
List::single,
t -> f.f(t).map(b -> set.f(b).f(s))
);
}
@Override
public F> modifyOptionF(final F> f) {
return s -> getOrModify.f(s).either(
Option.some_(),
t -> f.f(t).map(b -> set.f(b).f(s))
);
}
@Override
public F> modifyStreamF(final F> f) {
return s -> getOrModify.f(s).either(
Stream.single(),
t -> f.f(t).map(b -> set.f(b).f(s))
);
}
@Override
public F> modifyP1F(final F> f) {
return s -> getOrModify.f(s).either(
P.p1(),
t -> f.f(t).map(b -> set.f(b).f(s))
);
}
@Override
public F> modifyValidationF(final F> f) {
return s -> getOrModify.f(s).either(
Validation::success,
t -> f.f(t).map(b -> set.f(b).f(s))
);
}
@Override
public F> modifyV2F(final F> f) {
return s -> getOrModify.f(s).either(
t -> V2.p(P.p(t, t)),
t -> f.f(t).map(b -> set.f(b).f(s))
);
}
@Override
public F modify(final F f) {
return s -> getOrModify.f(s).either(Function.identity(), a -> set.f(f.f(a)).f(s));
}
};
}
}