fj.data.optic.PPrism 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.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 PPrism} can be seen as a pair of functions: - `getOrModify: S => T \/ A` - `reverseGet : B => T`
*
* A {@link PPrism} could also be defined as a weaker {@link PIso} where get can fail.
*
* Typically a {@link PPrism} or {@link Prism} encodes the relation between a Sum or CoProduct type (e.g. sealed trait) and one
* of it is element.
*
* {@link PPrism} stands for Polymorphic Prism as it set and modify methods change a type `A` to `B` and `S` to `T`.
* {@link Prism} is a {@link PPrism} where the type of target cannot be modified.
*
* A {@link PPrism} is also a valid {@link Fold}, {@link POptional}, {@link PTraversal} and {@link PSetter}
*
* @param the source of a {@link PPrism}
* @param the modified source of a {@link PPrism}
* @param the target of a {@link PPrism}
* @param the modified target of a {@link PPrism}
*/
public abstract class PPrism {
PPrism() {
super();
}
/** get the target of a {@link PPrism} or modify the source in case there is no target */
public abstract Either getOrModify(S s);
/** get the modified source of a {@link PPrism} */
public abstract T reverseGet(B b);
/** get the target of a {@link PPrism} or nothing if there is no target */
public abstract Option getOption(final S s);
/** modify polymorphically the target of a {@link PPrism} with an Applicative function */
public final F> modifyFunctionF(final F> f) {
return s -> getOrModify(s).either(
Function.constant(),
a -> Function.compose(this::reverseGet, f.f(a))
);
}
/** modify polymorphically the target of a {@link PPrism} with an Applicative function */
public final F> modifyEitherF(final F> f) {
return s -> getOrModify(s).either(
Either.right_(),
t -> f.f(t).right().map(this::reverseGet)
);
}
/** modify polymorphically the target of a {@link PPrism} with an Applicative function */
public final F> modifyIOF(final F> f) {
return s -> getOrModify(s).either(
IOFunctions::unit,
t -> IOFunctions.map(f.f(t), this::reverseGet)
);
}
/** modify polymorphically the target of a {@link PPrism} with an Applicative function */
public final F> modifyTrampolineF(final F> f) {
return s -> getOrModify(s).either(
Trampoline.pure(),
t -> f.f(t).map(this::reverseGet)
);
}
/** modify polymorphically the target of a {@link PPrism} with an Applicative function */
public final F> modifyPromiseF(final F> f) {
return s -> getOrModify(s).either(
t -> Promise.promise(Strategy.idStrategy(), P.p(t)),
t -> f.f(t).fmap(this::reverseGet)
);
}
/** modify polymorphically the target of a {@link PPrism} with an Applicative function */
public final F> modifyListF(final F> f) {
return s -> getOrModify(s).either(
List::single,
t -> f.f(t).map(this::reverseGet)
);
}
/** modify polymorphically the target of a {@link PPrism} with an Applicative function */
public final F> modifyOptionF(final F> f) {
return s -> getOrModify(s).either(
Option.some_(),
t -> f.f(t).map(this::reverseGet)
);
}
/** modify polymorphically the target of a {@link PPrism} with an Applicative function */
public final F> modifyStreamF(final F> f) {
return s -> getOrModify(s).either(
Stream.single(),
t -> f.f(t).map(this::reverseGet)
);
}
/** modify polymorphically the target of a {@link PPrism} with an Applicative function */
public final F> modifyP1F(final F> f) {
return s -> getOrModify(s).either(
P.p1(),
t -> f.f(t).map(this::reverseGet)
);
}
/** modify polymorphically the target of a {@link PPrism} with an Applicative function */
public final F> modifyValidationF(final F> f) {
return s -> getOrModify(s).either(
Validation::success,
t -> f.f(t).map(this::reverseGet)
);
}
/** modify polymorphically the target of a {@link PPrism} with an Applicative function */
public final F> modifyV2F(final F> f) {
return s -> getOrModify(s).either(
t -> V2.p(P.p(t, t)),
t -> f.f(t).map(this::reverseGet)
);
}
/** modify polymorphically the target of a {@link PPrism} with a function */
public final F modify(final F f) {
return s -> getOrModify(s).either(Function.identity(), a -> reverseGet(f.f(a)));
}
/** modify polymorphically the target of a {@link PPrism} with a function. return empty if the {@link PPrism} is not matching */
public final F> modifyOption(final F f) {
return s -> getOption(s).map(a -> reverseGet(f.f(a)));
}
/** set polymorphically the target of a {@link PPrism} with a value */
public final F set(final B b) {
return modify(Function.constant(b));
}
/** set polymorphically the target of a {@link PPrism} with a value. return empty if the {@link PPrism} is not matching */
public final F> setOption(final B b) {
return modifyOption(Function.constant(b));
}
/** check if a {@link PPrism} has a target */
public final boolean isMatching(final S s) {
return getOption(s).isSome();
}
/** create a {@link Getter} from the modified target to the modified source of a {@link PPrism} */
public final Getter re() {
return Getter.getter(this::reverseGet);
}
/************************************************************/
/** Compose methods between a {@link PPrism} and another Optics */
/************************************************************/
/** compose a {@link PPrism} with a {@link Fold} */
public final Fold composeFold(final Fold other) {
return asFold().composeFold(other);
}
/** compose a {@link PPrism} with a {@link Getter} */
public final Fold composeGetter(final Getter other) {
return asFold().composeGetter(other);
}
/** compose a {@link PPrism} with a {@link PSetter} */
public final PSetter composeSetter(final PSetter other) {
return asSetter().composeSetter(other);
}
/** compose a {@link PPrism} with a {@link PTraversal} */
public final PTraversal composeTraversal(final PTraversal other) {
return asTraversal().composeTraversal(other);
}
/** compose a {@link PPrism} with a {@link POptional} */
public final POptional composeOptional(final POptional other) {
return asOptional().composeOptional(other);
}
/** compose a {@link PPrism} with a {@link PLens} */
public final POptional composeLens(final PLens other) {
return asOptional().composeOptional(other.asOptional());
}
/** compose a {@link PPrism} with a {@link PPrism} */
public final PPrism composePrism(final PPrism other) {
return new PPrism() {
@Override
public Either getOrModify(final S s) {
return PPrism.this.getOrModify(s).right()
.bind(a -> other.getOrModify(a).bimap(b -> PPrism.this.set(b).f(s), Function.identity()));
}
@Override
public T reverseGet(final D d) {
return PPrism.this.reverseGet(other.reverseGet(d));
}
@Override
public Option getOption(final S s) {
return PPrism.this.getOption(s).bind(other::getOption);
}
};
}
/** compose a {@link PPrism} with a {@link PIso} */
public final PPrism composeIso(final PIso other) {
return composePrism(other.asPrism());
}
/******************************************************************/
/** Transformation methods to view a {@link PPrism} as another Optics */
/******************************************************************/
/** view a {@link PPrism} as a {@link Fold} */
public final Fold asFold() {
return new Fold() {
@Override
public F foldMap(final Monoid monoid, final F f) {
return s -> getOption(s).map(f).orSome(monoid.zero());
}
};
}
/** view a {@link PPrism} as a {@link Setter} */
public PSetter asSetter() {
return new PSetter() {
@Override
public F modify(final F f) {
return PPrism.this.modify(f);
}
@Override
public F set(final B b) {
return PPrism.this.set(b);
}
};
}
/** view a {@link PPrism} as a {@link PTraversal} */
public PTraversal asTraversal() {
final PPrism 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(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 -> getOption(s).map(f).orSome(monoid.zero());
}
};
}
/** view a {@link PPrism} as a {@link POptional} */
public POptional asOptional() {
final PPrism self = this;
return new POptional() {
@Override
public Either getOrModify(final S s) {
return self.getOrModify(s);
}
@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(final F> f) {
return self.modifyValidationF(f);
}
@Override
public F> modifyV2F(final F> f) {
return self.modifyV2F(f);
}
@Override
public F set(final B b) {
return self.set(b);
}
@Override
public Option getOption(final S s) {
return self.getOption(s);
}
@Override
public F modify(final F f) {
return self.modify(f);
}
};
}
public static PPrism pId() {
return PIso. pId().asPrism();
}
/** create a {@link PPrism} using the canonical functions: getOrModify and reverseGet */
public static PPrism pPrism(final F> getOrModify, final F reverseGet) {
return new PPrism() {
@Override
public Either getOrModify(final S s) {
return getOrModify.f(s);
}
@Override
public T reverseGet(final B b) {
return reverseGet.f(b);
}
@Override
public Option getOption(final S s) {
return getOrModify.f(s).right().toOption();
}
};
}
}