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

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

Go to download

Functional Java is an open source library that supports closures for the Java programming language

There is a newer version: 5.0
Show newest version
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.optionMonoid(), 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);
      }
    };
  }

}