fj.data.optic.PLens 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.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 PLens} can be seen as a pair of functions: - `get: S => A` i.e. from an `S`, we can extract an `A` - `set: (B, S) =>
* T` i.e. if we replace an `A` by a `B` in an `S`, we obtain a `T`
*
* A {@link PLens} could also be defined as a weaker {@link PIso} where set requires an additional parameter than reverseGet.
*
* {@link PLens} stands for Polymorphic Lens as it set and modify methods change a type `A` to `B` and `S` to `T`. {@link Lens}
* is a {@link PLens} restricted to monomoprhic updates.
*
* A {@link PLens} is also a valid {@link Getter}, {@link Fold}, {@link POptional}, {@link PTraversal} and {@link PSetter}
*
* Typically a {@link PLens} or {@link Lens} can be defined between a Product (e.g. case class, tuple, HList) and one of it is
* component.
*
* @param the source of a {@link PLens}
* @param the modified source of a {@link PLens}
* @param the target of a {@link PLens}
* @param the modified target of a {@link PLens}
*/
public abstract class PLens {
PLens() {
super();
}
/** get the target of a {@link PLens} */
public abstract A get(S s);
/** set polymorphically the target of a {@link PLens} using a function */
public abstract F set(B b);
/**
* modify polymorphically the target of a {@link PLens} with an Applicative function
*/
public abstract F> modifyFunctionF(F> f);
/**
* modify polymorphically the target of a {@link PLens} with an Applicative function
*/
public abstract F> modifyEitherF(F> f);
/**
* modify polymorphically the target of a {@link PLens} with an Applicative function
*/
public abstract F> modifyIOF(F> f);
/**
* modify polymorphically the target of a {@link PLens} with an Applicative function
*/
public abstract F> modifyTrampolineF(F> f);
/**
* modify polymorphically the target of a {@link PLens} with an Applicative function
*/
public abstract F> modifyPromiseF(F> f);
/**
* modify polymorphically the target of a {@link PLens} with an Applicative function
*/
public abstract F> modifyListF(F> f);
/**
* modify polymorphically the target of a {@link PLens} with an Applicative function
*/
public abstract F> modifyOptionF(F> f);
/**
* modify polymorphically the target of a {@link PLens} with an Applicative function
*/
public abstract F> modifyStreamF(F> f);
/**
* modify polymorphically the target of a {@link PLens} with an Applicative function
*/
public abstract F> modifyP1F(F> f);
/**
* modify polymorphically the target of a {@link PLens} with an Applicative function
*/
public abstract F> modifyValidationF(F> f);
/**
* modify polymorphically the target of a {@link PLens} with an Applicative function
*/
public abstract F> modifyV2F(F> f);
/** modify polymorphically the target of a {@link PLens} using a function */
public abstract F modify(final F f);
/** join two {@link PLens} with the same target */
public final PLens, Either, A, B> sum(final PLens other) {
return pLens(
e -> e.either(this::get, other::get),
b -> e -> e.bimap(PLens.this.set(b), other.set(b)));
}
/***********************************************************/
/** Compose methods between a {@link PLens} and another Optics */
/***********************************************************/
/** compose a {@link PLens} with a {@link Fold} */
public final Fold composeFold(final Fold other) {
return asFold().composeFold(other);
}
/** compose a {@link PLens} with a {@link Getter} */
public final Getter composeGetter(final Getter other) {
return asGetter().composeGetter(other);
}
/**
* compose a {@link PLens} with a {@link PSetter}
*/
public final PSetter composeSetter(final PSetter other) {
return asSetter().composeSetter(other);
}
/**
* compose a {@link PLens} with a {@link PTraversal}
*/
public final PTraversal composeTraversal(final PTraversal other) {
return asTraversal().composeTraversal(other);
}
/** compose a {@link PLens} with an {@link POptional} */
public final POptional composeOptional(final POptional other) {
return asOptional().composeOptional(other);
}
/** compose a {@link PLens} with a {@link PPrism} */
public final POptional composePrism(final PPrism other) {
return asOptional().composeOptional(other.asOptional());
}
/** compose a {@link PLens} with a {@link PLens} */
public final PLens composeLens(final PLens other) {
final PLens self = this;
return new PLens() {
@Override
public C get(final S s) {
return other.get(self.get(s));
}
@Override
public F set(final D d) {
return self.modify(other.set(d));
}
@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 PLens} with an {@link PIso} */
public final PLens composeIso(final PIso other) {
return composeLens(other.asLens());
}
/************************************************************************************************/
/** Transformation methods to view a {@link PLens} as another Optics */
/************************************************************************************************/
/** view a {@link PLens} as a {@link Fold} */
public final Fold asFold() {
return new Fold() {
@Override
public F foldMap(final Monoid m, final F f) {
return s -> f.f(get(s));
}
};
}
/** view a {@link PLens} as a {@link Getter} */
public final Getter asGetter() {
return new Getter() {
@Override
public A get(final S s) {
return PLens.this.get(s);
}
};
}
/** view a {@link PLens} as a {@link PSetter} */
public PSetter asSetter() {
return new PSetter() {
@Override
public F modify(final F f) {
return PLens.this.modify(f);
}
@Override
public F set(final B b) {
return PLens.this.set(b);
}
};
}
/** view a {@link PLens} as a {@link PTraversal} */
public PTraversal asTraversal() {
final PLens 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 -> f.f(get(s));
}
};
}
/** view a {@link PLens} as an {@link POptional} */
public POptional asOptional() {
final PLens self = this;
return new POptional() {
@Override
public Either getOrModify(final S s) {
return Either.right(self.get(s));
}
@Override
public F set(final B b) {
return self.set(b);
}
@Override
public Option getOption(final S s) {
return Option.some(self.get(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 modify(final F f) {
return self.modify(f);
}
};
}
public static PLens pId() {
return PIso. pId().asLens();
}
/**
* create a {@link PLens} using a pair of functions: one to get the target, one to set the target.
*/
public static PLens pLens(final F get, final F> set) {
return new PLens() {
@Override
public A get(final S s) {
return get.f(s);
}
@Override
public F set(final B b) {
return set.f(b);
}
@Override
public F> modifyFunctionF(final F> f) {
return s -> Function.compose(b -> set.f(b).f(s), f.f(get.f(s)));
}
@Override
public F> modifyEitherF(final F> f) {
return s -> f.f(get.f(s)).right().map(a -> set.f(a).f(s));
}
@Override
public F> modifyIOF(final F> f) {
return s -> IOFunctions.map(f.f(get.f(s)), a -> set.f(a).f(s));
}
@Override
public F> modifyTrampolineF(final F> f) {
return s -> f.f(get.f(s)).map(a -> set.f(a).f(s));
}
@Override
public F> modifyPromiseF(final F> f) {
return s -> f.f(get.f(s)).fmap(a -> set.f(a).f(s));
}
@Override
public F> modifyListF(final F> f) {
return s -> f.f(get.f(s)).map(a -> set.f(a).f(s));
}
@Override
public F> modifyOptionF(final F> f) {
return s -> f.f(get.f(s)).map(a -> set.f(a).f(s));
}
@Override
public F> modifyStreamF(final F> f) {
return s -> f.f(get.f(s)).map(a -> set.f(a).f(s));
}
@Override
public F> modifyP1F(final F> f) {
return s -> f.f(get.f(s)).map(a -> set.f(a).f(s));
}
@Override
public F> modifyValidationF(final F> f) {
return s -> f.f(get.f(s)).map(a -> set.f(a).f(s));
}
@Override
public F> modifyV2F(final F> f) {
return s -> f.f(get.f(s)).map(a -> set.f(a).f(s));
}
@Override
public F modify(final F f) {
return s -> set.f(f.f(get.f(s))).f(s);
}
};
}
}