
fj.data.optic.Fold Maven / Gradle / Ivy
package fj.data.optic;
import fj.F;
import fj.Function;
import fj.Monoid;
import fj.data.Either;
import fj.data.List;
import fj.data.Option;
/**
* A {@link Fold} can be seen as a {@link Getter} with many targets or a weaker {@link PTraversal} which cannot modify its
* target.
*
* {@link Fold} is on the top of the Optic hierarchy which means that {@link Getter}, {@link PTraversal}, {@link POptional},
* {@link PLens}, {@link PPrism} and {@link PIso} are valid {@link Fold}
*
* @param the source of a {@link Fold}
* @param the target of a {@link Fold}
*/
public abstract class Fold {
/**
* map each target to a {@link Monoid} and combine the results underlying representation of {@link Fold}, all {@link Fold}
* methods are defined in terms of foldMap
*/
public abstract F foldMap(Monoid m, 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 Fold} TODO: Shall it return a Stream as there might be an infinite number of targets?
*/
public final List getAll(final S s) {
return foldMap(Monoid.listMonoid(), List::single).f(s);
}
/** find the first target of a {@link Fold} 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 Fold} */
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);
}
/** join two {@link Fold} with the same target */
public final Fold, A> sum(final Fold other) {
return new Fold, A>() {
@Override
public F, B> foldMap(final Monoid m, final F f) {
return s -> s.either(Fold.this.foldMap(m, f), other.foldMap(m, f));
}
};
}
/**********************************************************/
/** Compose methods between a {@link Fold} and another Optics */
/**********************************************************/
/** compose a {@link Fold} with a {@link Fold} */
public final Fold composeFold(final Fold other) {
return new Fold() {
@Override
public F foldMap(final Monoid m, final F f) {
return Fold.this.foldMap(m, other. foldMap(m, f));
}
};
}
/** compose a {@link Fold} with a {@link Getter} */
public final Fold composeGetter(final Getter other) {
return composeFold(other.asFold());
}
/** compose a {@link Fold} with a {@link POptional} */
public final Fold composeOptional(final POptional other) {
return composeFold(other.asFold());
}
/** compose a {@link Fold} with a {@link PPrism} */
public final Fold composePrism(final PPrism other) {
return composeFold(other.asFold());
}
/** compose a {@link Fold} with a {@link PLens} */
public final Fold composeLens(final PLens other) {
return composeFold(other.asFold());
}
/** compose a {@link Fold} with a {@link PIso} */
public final Fold composeIso(final PIso other) {
return composeFold(other.asFold());
}
public static Fold id() {
return PIso. pId().asFold();
}
public static Fold, A> codiagonal() {
return new Fold, A>() {
@Override
public F, B> foldMap(final Monoid m, final F f) {
return e -> e.either(f, f);
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy