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

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

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:
    *
  • {@code getOrModify: S => T \/ A}
  • *
  • {@code 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 {@code A} to {@code B} and {@code S} to {@code T}. * {@link Optional} is a {@link POptional} restricted to monomoprhic updates: {@code 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)); } }; } }