fj.P1 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of functionaljava Show documentation
Show all versions of functionaljava Show documentation
Functional Java is an open source library that supports closures for the Java programming language
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