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

fj.P1 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;

import fj.data.Array;
import fj.data.Either;
import fj.data.List;
import fj.data.Option;
import fj.data.Stream;
import fj.data.Validation;

import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

import static fj.P.p;
import static fj.Unit.unit;
//import fj.data.*;


public abstract class P1 implements F0 {

    @Override
    public final A f() {
        return _1();
    }

    /**
     * Access the first element of the product.
     *
     * @return The first element of the product.
     */
    public abstract A _1();

    /**
     * Returns a function that returns the first element of a product.
     *
     * @return A function that returns the first element of a product.
     */
    public static  F, A> __1() {
        return P1::_1;
    }

    /**
     * Promote any function to a transformation between P1s.
     *
	 * @deprecated As of release 4.5, use {@link #map_}
     * @param f A function to promote to a transformation between P1s.
     * @return A function promoted to operate on P1s.
     */
    public static  F, P1> fmap(final F f) {
        return map_(f);
    }

	/**
	 * Promote any function to a transformation between P1s.
	 *
	 * @param f A function to promote to a transformation between P1s.
	 * @return A function promoted to operate on P1s.
	 */
	public static  F, P1> map_(final F f) {
		return a -> a.map(f);
	}

	/**
     * Binds the given function to the value in a product-1 with a final join.
     *
     * @param f A function to apply to the value in a product-1.
     * @return The result of applying the given function to the value of given product-1.
     */
    public final  P1 bind(final F> f) {
        P1 self = this;
        return P.lazy(() -> f.f(self._1())._1());
    }

    /**
     * Promotes the given function so that it returns its value in a P1.
     *
     * @param f A function to have its result wrapped in a P1.
     * @return A function whose result is wrapped in a P1.
     */
    public static  F> curry(final F f) {
        return a -> P.lazy(() -> f.f(a));
    }

    /**
     * Performs function application within a P1 (applicative functor pattern).
     *
     * @param cf The P1 function to apply.
     * @return A new P1 after applying the given P1 function to the first argument.
     */
    public final  P1 apply(final P1> cf) {
        P1 self = this;
        return cf.bind(f -> map_(f).f(self));
    }

    /**
     * Binds the given function to the values in the given P1s with a final join.
     *
     * @param cb A given P1 to bind the given function with.
     * @param f  The function to apply to the values in the given P1s.
     * @return A new P1 after performing the map, then final join.
     */
    public final  P1 bind(final P1 cb, final F> f) {
        return cb.apply(map_(f).f(this));
    }

	/**
	 * Binds the given function to the values in the given P1s with a final join.
	 */
	public final  P1 bind(final P1 cb, final F2 f) {
		return bind(cb, F2W.lift(f).curry());
	}

    /**
     * Joins a P1 of a P1 with a bind operation.
     *
     * @param a The P1 of a P1 to join.
     * @return A new P1 that is the join of the given P1.
     */
    public static  P1 join(final P1> a) {
        return a.bind(Function.identity());
    }

    /**
     * Promotes a function of arity-2 to a function on P1s.
     *
     * @param f The function to promote.
     * @return A function of arity-2 promoted to map over P1s.
     */
    public static  F, F, P1>> liftM2(final F> f) {
        return Function.curry((pa, pb) -> pa.bind(pb, f));
    }

	public final  P1 liftM2(P1 pb, F2 f) {
		return P.lazy(() -> f.f(_1(), pb._1()));
	}

    /**
     * Turns a List of P1s into a single P1 of a List.
     *
     * @param as The list of P1s to transform.
     * @return A single P1 for the given List.
     */
    public static  P1> sequence(final List> as) {
        return as.foldRight(liftM2(List.cons()), p(List.nil()));
    }

    /**
     * A first-class version of the sequence method for lists of P1s.
     *
     * @return A function from a List of P1s to a single P1 of a List.
     */
    public static  F>, P1>> sequenceList() {
        return P1::sequence;
    }

    /**
     * Turns a stream of P1s into a single P1 of a stream.
     *
     * @param as The stream of P1s to transform.
     * @return A single P1 for the given stream.
     */
    public static  P1> sequence(final Stream> as) {
        return as.foldRight(liftM2(Stream.cons()), p(Stream.nil()));
    }

	/**
	 * Turns an optional P1 into a lazy option.
	 */
	public static  P1> sequence(final Option> o) {
		return P.lazy(() -> o.map(P1::_1));
	}

    /**
     * Turns an array of P1s into a single P1 of an array.
     *
     * @param as The array of P1s to transform.
     * @return A single P1 for the given array.
     */
    public static  P1> sequence(final Array> as) {
        return P.lazy(() -> as.map(P1.__1()));
    }

    /**
     * Traversable instance of P1 for List
     *
     * @param f The function that takes A and produces a List (non-deterministic result)
     * @return A List of P1
     */
    public final  List> traverseList(final F> f){
        return f.f(_1()).map(P::p);
    }

    /**
     * Traversable instance of P1 for Either
     *
     * @param f The function produces Either
     * @return An Either of  P1
     */
    public final  Either> traverseEither(final F> f){
        return f.f(_1()).right().map(P::p);
    }

    /**
     * Traversable instance of P1 for Option
     *
     * @param f The function that produces Option
     * @return An Option of  P1
     */
    public final  Option> traverseOption(final F> f){
        return f.f(_1()).map(P::p);
    }

    /**
     * Traversable instance of P1 for Validation
     *
     * @param f The function might produces Validation
     * @return An Validation  of P1
     */
    public final  Validation> traverseValidation(final F> f){
        return f.f(_1()).map(P::p);
    }

    /**
     * Traversable instance of P1 for Stream
     *
     * @param f The function that produces Stream
     * @return An Stream of  P1
     */
    public final  Stream> traverseStream(final F> f){
        return f.f(_1()).map(P::p);
    }

    /**
       * Map the element of the product.
       *
       * @param f The function to map with.
       * @return A product with the given function applied.
       */
      public final  P1 map(final F f) {
          final P1 self = this;
        return P.lazy(() -> f.f(self._1()));
      }

    /**
     * @deprecated since 4.7. Use {@link P1#weakMemo()} instead.
     */
    @Deprecated
    public final P1 memo() {
        return weakMemo();
    }

    /**
     * Returns a P1 that remembers its value.
     *
     * @return A P1 that calls this P1 once and remembers the value for subsequent calls.
     */
    public P1 hardMemo() { return new Memo<>(this); }

    /**
     * Like memo, but the memoized value is wrapped into a WeakReference
     */
    public P1 weakMemo() { return new WeakReferenceMemo<>(this); }

    /**
     * Like memo, but the memoized value is wrapped into a SoftReference
     */
    public P1 softMemo() { return new SoftReferenceMemo<>(this); }

    /**
     * @deprecated since 4.7. Use {@link P#weakMemo(F0)} instead.
     */
    @Deprecated
    public static  P1 memo(F f) {
        return P.weakMemo(() -> f.f(unit()));
    }

  /**
   * @deprecated since 4.7. Use {@link P#weakMemo(F0)} instead.
   */
  @Deprecated
  public static  P1 memo(F0 f) {
		return P.weakMemo(f);
	}

    static final class Memo extends P1 {
      private volatile F0 fa;
      private A value;

      Memo(F0 fa) { this.fa = fa; }

      @Override public final A _1() {
        return (fa == null) ? value : computeValue();
      }

      private synchronized A computeValue() {
        F0 fa = this.fa;
        if (fa != null) {
          value = fa.f();
          this.fa = null;
        }
        return value;
      }

      @Override public P1 hardMemo() { return this; }
      @Override public P1 softMemo() { return this; }
      @Override public P1 weakMemo() { return this; }
    }

    abstract static class ReferenceMemo extends P1 {
      private final F0 fa;
      private volatile Reference> v = null;

      ReferenceMemo(final F0 fa) { this.fa = fa; }

      @Override public final A _1() {
        Reference> v = this.v;
        P1 p1 = v != null ? v.get() : null;
        return p1 != null ? p1._1() : computeValue();
      }

      private synchronized A computeValue() {
        Reference> v = this.v;
        P1 p1 = v != null ? v.get() : null;
        if (p1 == null) {
          A a = fa.f();
          this.v = newReference(p(a));
          return a;
        }
        return p1._1();
      }

      abstract  Reference newReference(B ref);
    }

    static final class WeakReferenceMemo extends ReferenceMemo {
      WeakReferenceMemo(F0 fa) { super(fa); }
      @Override
       Reference newReference(final B ref) { return new WeakReference<>(ref); }
      @Override public P1 weakMemo() { return this; }
    }

    static final class SoftReferenceMemo extends ReferenceMemo {
      SoftReferenceMemo(F0 self) { super(self); }
      @Override
       Reference newReference(final B ref) { return new SoftReference<>(ref); }
      @Override public P1 softMemo() { return this; }
      @Override public P1 weakMemo() { return this; }
    }

    /**
     * Returns a constant function that always uses this value.
     *
     * @return A constant function that always uses this value.
     */
    public final  F constant() { return Function.constant(_1()); }

    @Override
    public final String toString() {
		return Show.p1Show(Show.anyShow()).showS(this);
	}

    @Override
    public final boolean equals(Object other) {
        return Equal.equals0(P1.class, this, other, () -> Equal.p1Equal(Equal.anyEqual()));
    }

    @Override
    public final int hashCode() {
        return Hash.p1Hash(Hash.anyHash()).hash(this);
    }

}