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

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

package fj.data.optic;

import fj.F;
import fj.F3;
import fj.F4;
import fj.F5;
import fj.F6;
import fj.F7;
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.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 PTraversal} can be seen as a {@link POptional} generalised to 0 to n targets where n can be infinite.
 * 

* {@link PTraversal} stands for Polymorphic Traversal as it set and modify methods change a type {@code A} to {@code B} and {@code S} to {@code T}. * {@link Traversal} is a {@link PTraversal} restricted to monomoprhic updates.

* * @param the source of a {@link PTraversal} * @param the modified source of a {@link PTraversal} * @param the target of a {@link PTraversal} * @param the modified target of a {@link PTraversal} */ public abstract class PTraversal { /** * modify polymorphically the target of a {@link PTraversal} with an Applicative function */ public abstract F> modifyFunctionF(F> f); /** * modify polymorphically the target of a {@link PTraversal} with an Applicative function */ public abstract F> modifyEitherF(F> f); /** * modify polymorphically the target of a {@link PTraversal} with an Applicative function */ public abstract F> modifyIOF(F> f); /** * modify polymorphically the target of a {@link PTraversal} with an Applicative function */ public abstract F> modifyTrampolineF(F> f); /** * modify polymorphically the target of a {@link PTraversal} with an Applicative function */ public abstract F> modifyPromiseF(F> f); /** * modify polymorphically the target of a {@link PTraversal} with an Applicative function */ public abstract F> modifyListF(F> f); /** * modify polymorphically the target of a {@link PTraversal} with an Applicative function */ public abstract F> modifyOptionF(F> f); /** * modify polymorphically the target of a {@link PTraversal} with an Applicative function */ public abstract F> modifyStreamF(F> f); /** * modify polymorphically the target of a {@link PTraversal} with an Applicative function */ public abstract F> modifyP1F(F> f); /** * modify polymorphically the target of a {@link PTraversal} with an Applicative function */ public abstract F> modifyValidationF(Semigroup s, F> f); /** * modify polymorphically the target of a {@link PTraversal} with an Applicative function */ public abstract F> modifyV2F(F> f); /** map each target to a {@link Monoid} and combine the results */ public abstract F foldMap(Monoid monoid, F f); /** combine all targets using a target's {@link Monoid} */ public final F fold(final Monoid m) { return foldMap(m, Function.identity()); } /** get all the targets of a {@link PTraversal} */ public final List getAll(final S s) { return foldMap(Monoid.listMonoid(), List::single).f(s); } /** find the first target of a {@link PTraversal} matching the predicate */ public final F> find(final F p) { return foldMap(Monoid.firstOptionMonoid(), a -> p.f(a) ? Option.some(a) : Option.none()); } /** get the first target of a {@link PTraversal} */ public final Option headOption(final S s) { return find(Function.constant(Boolean.TRUE)).f(s); } /** check if at least one target satisfies the predicate */ public final F exist(final F p) { return foldMap(Monoid.disjunctionMonoid, p); } /** check if all targets satisfy the predicate */ public final F all(final F p) { return foldMap(Monoid.conjunctionMonoid, p); } /** modify polymorphically the target of a {@link PTraversal} with a function */ public final F modify(final F f) { return s -> this.modifyP1F(a -> P.p(f.f(a))).f(s)._1(); } /** set polymorphically the target of a {@link PTraversal} with a value */ public final F set(final B b) { return modify(Function.constant(b)); } /** join two {@link PTraversal} with the same target */ public final PTraversal, Either, A, B> sum(final PTraversal other) { final PTraversal self = this; return new PTraversal, Either, A, B>() { @Override public F, F>> modifyFunctionF(final F> f) { return ss1 -> ss1.either( s -> Function.compose(Either.left_(), self.modifyFunctionF(f).f(s)), s1 -> Function.compose(Either.right_(), other.modifyFunctionF(f).f(s1)) ); } @Override public F, Either>> modifyEitherF(final F> f) { return ss1 -> ss1.either( s -> self.modifyEitherF(f).f(s).right().map(Either.left_()), s1 -> other.modifyEitherF(f).f(s1).right().map(Either.right_()) ); } @Override public F, IO>> modifyIOF(final F> f) { return ss1 -> ss1.either( s -> IOFunctions.map(self.modifyIOF(f).f(s), Either.left_()), s1 -> IOFunctions.map(other.modifyIOF(f).f(s1), Either.right_()) ); } @Override public F, Trampoline>> modifyTrampolineF(final F> f) { return ss1 -> ss1.either( s -> self.modifyTrampolineF(f).f(s).map(Either.left_()), s1 -> other.modifyTrampolineF(f).f(s1).map(Either.right_()) ); } @Override public F, Promise>> modifyPromiseF(final F> f) { return ss1 -> ss1.either( s -> self.modifyPromiseF(f).f(s).fmap(Either.left_()), s1 -> other.modifyPromiseF(f).f(s1).fmap(Either.right_()) ); } @Override public F, List>> modifyListF(final F> f) { return ss1 -> ss1.either( s -> self.modifyListF(f).f(s).map(Either.left_()), s1 -> other.modifyListF(f).f(s1).map(Either.right_()) ); } @Override public F, Option>> modifyOptionF(final F> f) { return ss1 -> ss1.either( s -> self.modifyOptionF(f).f(s).map(Either.left_()), s1 -> other.modifyOptionF(f).f(s1).map(Either.right_()) ); } @Override public F, Stream>> modifyStreamF(final F> f) { return ss1 -> ss1.either( s -> self.modifyStreamF(f).f(s).map(Either.left_()), s1 -> other.modifyStreamF(f).f(s1).map(Either.right_()) ); } @Override public F, P1>> modifyP1F(final F> f) { return ss1 -> ss1.either( s -> self.modifyP1F(f).f(s).map(Either.left_()), s1 -> other.modifyP1F(f).f(s1).map(Either.right_()) ); } @Override public F, V2>> modifyV2F(final F> f) { return ss1 -> ss1.either( s -> self.modifyV2F(f).f(s).map(Either.left_()), s1 -> other.modifyV2F(f).f(s1).map(Either.right_()) ); } @Override public F, Validation>> modifyValidationF(Semigroup se, final F> f) { return ss1 -> ss1.either( s -> self.modifyValidationF(se, f).f(s).map(Either.left_()), s1 -> other.modifyValidationF(se, f).f(s1).map(Either.right_()) ); } @Override public F, M> foldMap(final Monoid monoid, final F f) { return ss1 -> ss1.either( self.foldMap(monoid, f), other.foldMap(monoid, f) ); } }; } /****************************************************************/ /** Compose methods between a {@link PTraversal} and another Optics */ /****************************************************************/ /** compose a {@link PTraversal} with a {@link Fold} */ public final Fold composeFold(final Fold other) { return asFold().composeFold(other); } // /** compose a {@link PTraversal} with a {@link Getter} */ public final Fold composeFold(final Getter other) { return asFold().composeGetter(other); } /** compose a {@link PTraversal} with a {@link PSetter} */ public final PSetter composeSetter(final PSetter other) { return asSetter().composeSetter(other); } /** compose a {@link PTraversal} with a {@link PTraversal} */ public final PTraversal composeTraversal(final PTraversal other) { final PTraversal self = this; return new PTraversal() { @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(Semigroup s, final F> f) { return self.modifyValidationF(s, other.modifyValidationF(s, f)); } @Override public F> modifyV2F(final F> f) { return self.modifyV2F(other.modifyV2F(f)); } @Override public F foldMap(final Monoid monoid, final F f) { return self.foldMap(monoid, other.foldMap(monoid, f)); } }; } /** compose a {@link PTraversal} with a {@link POptional} */ public final PTraversal composeOptional(final POptional other) { return composeTraversal(other.asTraversal()); } /** compose a {@link PTraversal} with a {@link PPrism} */ public final PTraversal composePrism(final PPrism other) { return composeTraversal(other.asTraversal()); } /** compose a {@link PTraversal} with a {@link PLens} */ public final PTraversal composeLens(final PLens other) { return composeTraversal(other.asTraversal()); } /** compose a {@link PTraversal} with a {@link PIso} */ public final PTraversal composeIso(final PIso other) { return composeTraversal(other.asTraversal()); } /**********************************************************************/ /** Transformation methods to view a {@link PTraversal} as another Optics */ /**********************************************************************/ /** view a {@link PTraversal} as a {@link Fold} */ public final Fold asFold() { return new Fold() { @Override public F foldMap(final Monoid monoid, final F f) { return PTraversal.this.foldMap(monoid, f); } }; } /** view a {@link PTraversal} as a {@link PSetter} */ public PSetter asSetter() { return PSetter.pSetter(this::modify); } public static PTraversal pId() { return PIso. pId().asTraversal(); } public static PTraversal, Either, S, T> pCodiagonal() { return new PTraversal, Either, S, T>() { @Override public F, F>> modifyFunctionF(final F> f) { return s -> s.bimap(f, f).either( f1 -> Function.compose(Either.left_(), f1), f1 -> Function.compose(Either.right_(), f1) ); } @Override public F, Either>> modifyEitherF(final F> f) { return s -> s.bimap(f, f).either( e -> e.right().map(Either.left_()), e -> e.right().map(Either.right_()) ); } @Override public F, IO>> modifyIOF(final F> f) { return s -> s.bimap(f, f).either( io -> IOFunctions.map(io, Either.left_()), io -> IOFunctions.map(io, Either.right_()) ); } @Override public F, Trampoline>> modifyTrampolineF(final F> f) { return s -> s.bimap(f, f).either( t -> t.map(Either.left_()), t -> t.map(Either.right_()) ); } @Override public F, Promise>> modifyPromiseF(final F> f) { return s -> s.bimap(f, f).either( p -> p.fmap(Either.left_()), p -> p.fmap(Either.right_()) ); } @Override public F, List>> modifyListF(final F> f) { return s -> s.bimap(f, f).either( l -> l.map(Either.left_()), l -> l.map(Either.right_()) ); } @Override public F, Option>> modifyOptionF(final F> f) { return s -> s.bimap(f, f).either( o -> o.map(Either.left_()), o -> o.map(Either.right_()) ); } @Override public F, Stream>> modifyStreamF(final F> f) { return s -> s.bimap(f, f).either( stream -> stream.map(Either.left_()), stream -> stream.map(Either.right_()) ); } @Override public F, P1>> modifyP1F(final F> f) { return s -> s.bimap(f, f).either( p1 -> p1.map(Either.left_()), p1 -> p1.map(Either.right_()) ); } @Override public F, V2>> modifyV2F(final F> f) { return s -> s.bimap(f, f).either( v2 -> v2.map(Either.left_()), v2 -> v2.map(Either.right_()) ); } @Override public F, Validation>> modifyValidationF(Semigroup se, final F> f) { return s -> s.bimap(f, f).either( v -> v.map(Either.left_()), v -> v.map(Either.right_()) ); } @Override public F, M> foldMap(final Monoid monoid, final F f) { return s -> s.either(f, f); } }; } public static PTraversal pTraversal(final F get1, final F get2, final F3 set) { return new PTraversal() { @Override public F> modifyFunctionF(final F> f) { return s -> Function.apply(Function.compose(b1 -> b2 -> set.f(b1, b2, s), f.f(get1.f(s))), f.f(get2.f(s))); } @Override public F> modifyEitherF(final F> f) { return s -> f.f(get2.f(s)).right().apply(f.f(get1.f(s)).right().> map(b1 -> b2 -> set.f(b1, b2, s))); } @Override public F> modifyIOF(final F> f) { return s -> IOFunctions.apply(f.f(get2.f(s)), IOFunctions.> map(f.f(get1.f(s)), b1 -> b2 -> set.f(b1, b2, s))); } @Override public F> modifyTrampolineF(final F> f) { return s -> f.f(get2.f(s)).apply(f.f(get1.f(s)).> map(b1 -> b2 -> set.f(b1, b2, s))); } @Override public F> modifyPromiseF(final F> f) { return s -> f.f(get2.f(s)).apply(f.f(get1.f(s)).> fmap(b1 -> b2 -> set.f(b1, b2, s))); } @Override public F> modifyListF(final F> f) { return s -> f.f(get2.f(s)).apply(f.f(get1.f(s)).> map(b1 -> b2 -> set.f(b1, b2, s))); } @Override public F> modifyOptionF(final F> f) { return s -> f.f(get2.f(s)).apply(f.f(get1.f(s)).> map(b1 -> b2 -> set.f(b1, b2, s))); } @Override public F> modifyStreamF(final F> f) { return s -> f.f(get2.f(s)).apply(f.f(get1.f(s)).> map(b1 -> b2 -> set.f(b1, b2, s))); } @Override public F> modifyP1F(final F> f) { return s -> f.f(get2.f(s)).apply(f.f(get1.f(s)).> map(b1 -> b2 -> set.f(b1, b2, s))); } @Override public F> modifyV2F(final F> f) { return s -> f.f(get2.f(s)).apply(f.f(get1.f(s)).> map(b1 -> b2 -> set.f(b1, b2, s))); } @Override public F> modifyValidationF(Semigroup se, final F> f) { return s -> f.f(get2.f(s)).accumapply(se, f.f(get1.f(s)).> map(b1 -> b2 -> set.f(b1, b2, s))); } @Override public F foldMap(final Monoid monoid, final F f) { return s -> monoid.sum(f.f(get1.f(s)), f.f(get2.f(s))); } }; } public static PTraversal pTraversal(final F get1, final F get2, final F get3, final F4 set) { return fromCurried(pTraversal(get1, get2, (b1, b2, s) -> b3 -> set.f(b1, b2, b3, s)), get3); } public static PTraversal pTraversal(final F get1, final F get2, final F get3, final F get4, final F5 set) { return fromCurried(pTraversal(get1, get2, get3, (b1, b2, b3, s) -> b4 -> set.f(b1, b2, b3, b4, s)), get4); } public static PTraversal pTraversal(final F get1, final F get2, final F get3, final F get4, final F get5, final F6 set) { return fromCurried(pTraversal(get1, get2, get3, get4, (b1, b2, b3, b4, s) -> b5 -> set.f(b1, b2, b3, b4, b5, s)), get5); } public static PTraversal pTraversal(final F get1, final F get2, final F get3, final F get4, final F get5, final F get6, final F7 set) { return fromCurried( pTraversal(get1, get2, get3, get4, get5, (b1, b2, b3, b4, b5, s) -> b6 -> set.f(b1, b2, b3, b4, b5, b6, s)), get6); } private static PTraversal fromCurried(final PTraversal, A, B> curriedTraversal, final F lastGet) { return new PTraversal() { @Override public F> modifyFunctionF(final F> f) { return s -> Function.apply(curriedTraversal.modifyFunctionF(f).f(s), f.f(lastGet.f(s))); } @Override public F> modifyEitherF(final F> f) { return s -> f.f(lastGet.f(s)).right().apply(curriedTraversal.modifyEitherF(f).f(s)); } @Override public F> modifyIOF(final F> f) { return s -> IOFunctions.apply(f.f(lastGet.f(s)), curriedTraversal.modifyIOF(f).f(s)); } @Override public F> modifyTrampolineF(final F> f) { return s -> f.f(lastGet.f(s)).apply(curriedTraversal.modifyTrampolineF(f).f(s)); } @Override public F> modifyPromiseF(final F> f) { return s -> f.f(lastGet.f(s)).apply(curriedTraversal.modifyPromiseF(f).f(s)); } @Override public F> modifyListF(final F> f) { return s -> f.f(lastGet.f(s)).apply(curriedTraversal.modifyListF(f).f(s)); } @Override public F> modifyOptionF(final F> f) { return s -> f.f(lastGet.f(s)).apply(curriedTraversal.modifyOptionF(f).f(s)); } @Override public F> modifyStreamF(final F> f) { return s -> f.f(lastGet.f(s)).apply(curriedTraversal.modifyStreamF(f).f(s)); } @Override public F> modifyP1F(final F> f) { return s -> f.f(lastGet.f(s)).apply(curriedTraversal.modifyP1F(f).f(s)); } @Override public F> modifyV2F(final F> f) { return s -> f.f(lastGet.f(s)).apply(curriedTraversal.modifyV2F(f).f(s)); } @Override public F> modifyValidationF(Semigroup se, final F> f) { return s -> f.f(lastGet.f(s)).accumapply(se, curriedTraversal.modifyValidationF(se, f).f(s)); } @Override public F foldMap(final Monoid monoid, final F f) { return s -> monoid.sum(curriedTraversal.foldMap(monoid, f).f(s), f.f(lastGet.f(s))); } }; } }