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

fj.data.optic.PLens 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.P1;
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(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 final  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);
      }
    };
  }
}