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.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: - `getOrModify: S => T \/ A` - `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 `A` to `B` and `S` to `T`.
* {@link Optional} is a {@link POptional} restricted to monomoprhic updates: {{{ 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(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 final 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(
t -> Validation. success(t),
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));
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy