fj.data.optic.PPrism Maven / Gradle / Ivy
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(
t -> Validation. success(t),
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();
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy