All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fj.data.optic.PPrism Maven / Gradle / Ivy

Go to download

Functional Java is an open source library that supports closures for the Java programming language

The newest version!
package fj.data.optic;

import fj.F;
import fj.Function;
import fj.Monoid;
import fj.P;
import fj.P1;
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 PPrism} can be seen as a pair of functions:
    *
  • {@code getOrModify: S => T \/ A}
  • *
  • {@code 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 {@code A} to {@code B} and {@code S} to {@code 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(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 -> 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(); } }; } }