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 java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

import fj.data.Array;
import fj.data.List;
import fj.data.Stream;
import fj.data.Either;
import fj.data.Option;
import fj.data.Validation;
//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 p -> p._1();
    }

    /**
     * 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> fmap(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  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  P1 apply(final P1> cf) {
        P1 self = this;
        return cf.bind(f -> fmap(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  P1 bind(final P1 cb, final F> f) {
        return cb.apply(fmap(f).f(this));
    }

    /**
     * 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));
    }

    /**
     * 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.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 as -> sequence(as);
    }

    /**
     * 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.p(Stream.nil()));
    }

    /**
     * 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  List> traverseList(final F>  f){
        return f.f(_1()).map(b -> P.p(b));
    }

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

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

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

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

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

    public 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); }

    static  P1 memo(F f) {
        return P.lazy(f).memo();
    }

    static class Memo extends P1 {
      private final P1 self;
      private volatile boolean initialized;
      private A value;

      Memo(P1 self) { this.self = self; }

      @Override public A _1() {
        if (!initialized) {
          synchronized (this) {
            if (!initialized) {
              A a = self._1();
              value = a;
              initialized = true;
              return a;
            }
          }
        }
        return value;
      }

      @Override public P1 memo() { return this; }
    }

    abstract static class ReferenceMemo extends P1 {
      private final P1 self;
      private final Object latch = new Object();
      private volatile Reference> v = null;

      ReferenceMemo(final P1 self) { this.self = self; }

      @Override public A _1() {
        Option o = v != null ? v.get() : null;
        if (o == null) {
          synchronized (latch) {
            o = v != null ? v.get() : null;
            if (o == null) {
              o = Option.some(self._1());
              v = newReference(o);
            }
          }
        }
        return o.some();
      }

      abstract Reference> newReference(Option o);
    }

    static class WeakReferenceMemo extends ReferenceMemo {
      WeakReferenceMemo(P1 self) { super(self); }
      @Override Reference> newReference(final Option o) { return new WeakReference<>(o); }
      @Override public P1 weakMemo() { return this; }
    }

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

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

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

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

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

}