001    package fj;
002    
003    import fj.data.List;
004    import fj.data.Stream;
005    import fj.data.Array;
006    import fj.data.Option;
007    import static fj.data.Option.none;
008    import static fj.data.Option.some;
009    import static fj.data.Option.fromNull;
010    
011    import java.util.concurrent.CountDownLatch;
012    import java.util.concurrent.atomic.AtomicReference;
013    import java.lang.ref.WeakReference;
014    import java.lang.ref.SoftReference;
015    
016    /**
017     * A product-1. Also, the identity monad.
018     *
019     * @version %build.number%<br>
020     *          <ul>
021     *          <li>$LastChangedRevision: 273 $</li>
022     *          <li>$LastChangedDate: 2009-08-04 06:25:29 +1000 (Tue, 04 Aug 2009) $</li>
023     *          </ul>
024     */
025    public abstract class P1<A> {
026      /**
027       * Access the first element of the product.
028       *
029       * @return The first element of the product.
030       */
031      public abstract A _1();
032    
033      /**
034       * Map the element of the product.
035       *
036       * @param f The function to map with.
037       * @return A product with the given function applied.
038       */
039      public <X> P1<X> map(final F<A, X> f) {
040        return new P1<X>() {
041          public X _1() {
042            return f.f(P1.this._1());
043          }
044        };
045      }
046    
047      /**
048       * Returns a function that returns the first element of a product.
049       *
050       * @return A function that returns the first element of a product.
051       */
052      public static <A> F<P1<A>, A> __1() {
053        return new F<P1<A>, A>() {
054          public A f(final P1<A> p) {
055            return p._1();
056          }
057        };
058      }
059    
060      /**
061       * Promote any function to a transformation between P1s.
062       *
063       * @param f A function to promote to a transformation between P1s.
064       * @return A function promoted to operate on P1s.
065       */
066      public static <A, B> F<P1<A>, P1<B>> fmap(final F<A, B> f) {
067        return new F<P1<A>, P1<B>>() {
068          public P1<B> f(final P1<A> a) {
069            return a.map(f);
070          }
071        };
072      }
073    
074      /**
075       * Binds the given function to the value in a product-1 with a final join.
076       *
077       * @param a A value in a product-1 to which to apply a function.
078       * @param f A function to apply to the value in a product-1.
079       * @return The result of applying the given function to the value of given product-1.
080       */
081      public static <A, B> P1<B> bind(final P1<A> a, final F<A, P1<B>> f) {
082        return new P1<B>() {
083          public B _1() {
084            return f.f(a._1())._1();
085          }
086        };
087      }
088    
089      /**
090       * Promotes the given function so that it returns its value in a P1.
091       *
092       * @param f A function to have its result wrapped in a P1.
093       * @return A function whose result is wrapped in a P1.
094       */
095      public static <A, B> F<A, P1<B>> curry(final F<A, B> f) {
096        return new F<A, P1<B>>() {
097          public P1<B> f(final A a) {
098            return new P1<B>() {
099              public B _1() {
100                return f.f(a);
101              }
102            };
103          }
104        };
105      }
106    
107      /**
108       * Performs function application within a P1 (applicative functor pattern).
109       *
110       * @param ca The P1 to which to apply a function.
111       * @param cf The P1 function to apply.
112       * @return A new P1 after applying the given P1 function to the first argument.
113       */
114      public static <A, B> P1<B> apply(final P1<A> ca, final P1<F<A, B>> cf) {
115        return bind(cf, new F<F<A, B>, P1<B>>() {
116          public P1<B> f(final F<A, B> f) {
117            return fmap(f).f(ca);
118          }
119        });
120      }
121    
122      /**
123       * Binds the given function to the values in the given P1s with a final join.
124       *
125       * @param ca A given P1 to bind the given function with.
126       * @param cb A given P1 to bind the given function with.
127       * @param f  The function to apply to the values in the given P1s.
128       * @return A new P1 after performing the map, then final join.
129       */
130      public static <A, B, C> P1<C> bind(final P1<A> ca, final P1<B> cb, final F<A, F<B, C>> f) {
131        return apply(cb, fmap(f).f(ca));
132      }
133    
134      /**
135       * Joins a P1 of a P1 with a bind operation.
136       *
137       * @param a The P1 of a P1 to join.
138       * @return A new P1 that is the join of the given P1.
139       */
140      public static <A> P1<A> join(final P1<P1<A>> a) {
141        return bind(a, Function.<P1<A>>identity());
142      }
143    
144      /**
145       * Promotes a function of arity-2 to a function on P1s.
146       *
147       * @param f The function to promote.
148       * @return A function of arity-2 promoted to map over P1s.
149       */
150      public static <A, B, C> F<P1<A>, F<P1<B>, P1<C>>> liftM2(final F<A, F<B, C>> f) {
151        return Function.curry(new F2<P1<A>, P1<B>, P1<C>>() {
152          public P1<C> f(final P1<A> pa, final P1<B> pb) {
153            return bind(pa, pb, f);
154          }
155        });
156      }
157    
158      /**
159       * Turns a List of P1s into a single P1 of a List.
160       *
161       * @param as The list of P1s to transform.
162       * @return A single P1 for the given List.
163       */
164      public static <A> P1<List<A>> sequence(final List<P1<A>> as) {
165        return as.foldRight(liftM2(List.<A>cons()), P.p(List.<A>nil()));
166      }
167    
168      /**
169       * A first-class version of the sequence method for lists of P1s.
170       *
171       * @return A function from a List of P1s to a single P1 of a List.
172       */
173      public static <A> F<List<P1<A>>, P1<List<A>>> sequenceList() {
174        return new F<List<P1<A>>, P1<List<A>>>() {
175          public P1<List<A>> f(final List<P1<A>> as) {
176            return sequence(as);
177          }
178        };
179      }
180    
181      /**
182       * Turns a stream of P1s into a single P1 of a stream.
183       *
184       * @param as The stream of P1s to transform.
185       * @return A single P1 for the given stream.
186       */
187      public static <A> P1<Stream<A>> sequence(final Stream<P1<A>> as) {
188        return as.foldRight(liftM2(Stream.<A>cons()), P.p(Stream.<A>nil()));
189      }
190    
191      /**
192       * Turns an array of P1s into a single P1 of an array.
193       *
194       * @param as The array of P1s to transform.
195       * @return A single P1 for the given array.
196       */
197      public static <A> P1<Array<A>> sequence(final Array<P1<A>> as) {
198        return new P1<Array<A>>() {
199          public Array<A> _1() {
200            return as.map(P1.<A>__1());
201          }
202        };
203      }
204    
205      /**
206       * Provides a memoising P1 that remembers its value.
207       *
208       * @return A P1 that calls this P1 once and remembers the value for subsequent calls.
209       */
210      public P1<A> memo() {
211        final P1<A> self = this;
212        return new P1<A>() {
213          private Object latch = new Object();
214          private volatile SoftReference<A> v;
215    
216          public A _1() {
217            A a = v != null ? v.get() : null;
218            if (a == null)
219              synchronized (latch) {
220                if (v == null || v.get() == null)
221                  a = self._1();
222                v = new SoftReference<A>(a);
223              }
224            return a;
225          }
226        };
227      }
228    
229    }