Mercurial > hg > Members > tatsuki > functionaljava-master > core
view src/main/java/fj/P1.java @ 0:fe80c1edf1be
add getLoop
author | tatsuki |
---|---|
date | Fri, 20 Mar 2015 21:04:03 +0900 |
parents | |
children |
line wrap: on
line source
package fj; import java.lang.ref.SoftReference; import fj.data.Array; import fj.data.List; import fj.data.Stream; import fj.data.Validation; import fj.function.Try0; public abstract class P1<A> { /** * 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 <A> F<P1<A>, A> __1() { return new F<P1<A>, A>() { public A f(final P1<A> 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 <A, B> F<P1<A>, P1<B>> fmap(final F<A, B> f) { return new F<P1<A>, P1<B>>() { public P1<B> f(final P1<A> a) { return 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 <B> P1<B> bind(final F<A, P1<B>> f) { P1<A> self = this; return new P1<B>() { public B _1() { return 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 <A, B> F<A, P1<B>> curry(final F<A, B> f) { return new F<A, P1<B>>() { public P1<B> f(final A a) { return new P1<B>() { public B _1() { return 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 <B> P1<B> apply(final P1<F<A, B>> cf) { P1<A> self = this; return cf.bind(new F<F<A, B>, P1<B>>() { public P1<B> f(final F<A, B> f) { return 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 <B, C> P1<C> bind(final P1<B> cb, final F<A, F<B, C>> 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 <A> P1<A> join(final P1<P1<A>> a) { return a.bind(Function.<P1<A>>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 <A, B, C> F<P1<A>, F<P1<B>, P1<C>>> liftM2(final F<A, F<B, C>> f) { return Function.curry(new F2<P1<A>, P1<B>, P1<C>>() { public P1<C> f(final P1<A> pa, final P1<B> pb) { return 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 <A> P1<List<A>> sequence(final List<P1<A>> as) { return as.foldRight(liftM2(List.<A>cons()), P.p(List.<A>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 <A> F<List<P1<A>>, P1<List<A>>> sequenceList() { return new F<List<P1<A>>, P1<List<A>>>() { public P1<List<A>> f(final List<P1<A>> 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 <A> P1<Stream<A>> sequence(final Stream<P1<A>> as) { return as.foldRight(liftM2(Stream.<A>cons()), P.p(Stream.<A>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 <A> P1<Array<A>> sequence(final Array<P1<A>> as) { return new P1<Array<A>>() { public Array<A> _1() { return as.map(P1.<A>__1()); } }; } /** * Map the element of the product. * * @param f The function to map with. * @return A product with the given function applied. */ public <X> P1<X> map(final F<A, X> f) { final P1<A> self = this; return new P1<X>() { public X _1() { return f.f(self._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 P1<A> memo() { final P1<A> self = this; return new P1<A>() { private final Object latch = new Object(); @SuppressWarnings({"InstanceVariableMayNotBeInitialized"}) private volatile SoftReference<A> 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>(a); } return a; } }; } static <A> P1<A> memo(F<Unit, A> f) { return P.lazy(f).memo(); } /** * Returns a constant function that always uses this value. * * @return A constant function that always uses this value. */ public <B> F<B, A> constant() { return new F<B, A>() { public A f(final B b) { return P1.this._1(); } }; } public String toString() { return Show.p1Show(Show.<A>anyShow()).showS(this); } }