package fj;
import fj.data.List;
import fj.data.Stream;
import fj.data.Array;
import java.lang.ref.SoftReference;
/**
* A product-1. Also, the identity monad.
*
* @version %build.number%
*/
public abstract class P1 {
/**
* Access the first element of the product.
*
* @return The first element of the product.
*/
public abstract A _1();
/**
* 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) {
return new P1() {
public X _1() {
return f.f(P1.this._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 new F, A>() {
public A f(final P1 p) {
return 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 new F, P1>() {
public P1 f(final P1 a) {
return a.map(f);
}
};
}
/**
* Binds the given function to the value in a product-1 with a final join.
*
* @param a A value in a product-1 to which to apply a function.
* @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 static P1 bind(final P1 a, final F> f) {
return new P1() {
public B _1() {
return f.f(a._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 new F>() {
public P1 f(final A a) {
return new P1() {
public B _1() {
return f.f(a);
}
};
}
};
}
/**
* Performs function application within a P1 (applicative functor pattern).
*
* @param ca The P1 to which to apply a function.
* @param cf The P1 function to apply.
* @return A new P1 after applying the given P1 function to the first argument.
*/
public static P1 apply(final P1 ca, final P1> cf) {
return bind(cf, new F, P1>() {
public P1 f(final F f) {
return fmap(f).f(ca);
}
});
}
/**
* Binds the given function to the values in the given P1s with a final join.
*
* @param ca A given P1 to bind the given function with.
* @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 static P1 bind(final P1 ca, final P1 cb, final F> f) {
return apply(cb, fmap(f).f(ca));
}
/**
* 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 bind(a, 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(new F2, P1, P1>() {
public P1 f(final P1 pa, final P1 pb) {
return bind(pa, 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 new F>, P1>>() {
public P1> f(final List> as) {
return 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 new P1>() {
public Array _1() {
return as.map(P1.__1());
}
};
}
/**
* Provides a memoising P1 that remembers its value.
*
* @return A P1 that calls this P1 once and remembers the value for subsequent calls.
*/
public final P1 memo() {
final P1 self = this;
return new P1() {
private final Object latch = new Object();
@SuppressWarnings({"InstanceVariableMayNotBeInitialized"})
private volatile SoftReference v;
public A _1() {
A a = v != null ? v.get() : null;
if (a == null)
synchronized (latch) {
if (v == null || v.get() == null)
a = self._1();
v = new SoftReference(a);
}
return a;
}
};
}
/**
* Returns a constant function that always uses this value.
*
* @return A constant function that always uses this value.
*/
public final F constant() {
return new F() {
public A f(final B b) {
return _1();
}
};
}
}