001    package fj;
002    
003    import static fj.Function.*;
004    import fj.data.List;
005    import fj.data.Stream;
006    import static fj.FW.$;
007    
008    /**
009     * A product-2.
010     *
011     * @version %build.number%<br>
012     *          <ul>
013     *          <li>$LastChangedRevision: 270 $</li>
014     *          <li>$LastChangedDate: 2009-07-28 14:06:27 +1000 (Tue, 28 Jul 2009) $</li>
015     *          </ul>
016     */
017    public abstract class P2<A, B> {
018      /**
019       * Access the first element of the product.
020       *
021       * @return The first element of the product.
022       */
023      public abstract A _1();
024    
025      /**
026       * Access the second element of the product.
027       *
028       * @return The second element of the product.
029       */
030      public abstract B _2();
031    
032      /**
033       * Swaps the elements around in this product.
034       *
035       * @return A new product-2 with the elements swapped.
036       */
037      public P2<B, A> swap() {
038        return new P2<B, A>() {
039          public B _1() {
040            return P2.this._2();
041          }
042    
043          public A _2() {
044            return P2.this._1();
045          }
046        };
047      }
048    
049      /**
050       * Map the first element of the product.
051       *
052       * @param f The function to map with.
053       * @return A product with the given function applied.
054       */
055      public <X> P2<X, B> map1(final F<A, X> f) {
056        return new P2<X, B>() {
057          public X _1() {
058            return f.f(P2.this._1());
059          }
060    
061          public B _2() {
062            return P2.this._2();
063          }
064        };
065      }
066    
067      /**
068       * Map the second element of the product.
069       *
070       * @param f The function to map with.
071       * @return A product with the given function applied.
072       */
073      public <X> P2<A, X> map2(final F<B, X> f) {
074        return new P2<A, X>() {
075          public A _1() {
076            return P2.this._1();
077          }
078    
079          public X _2() {
080            return f.f(P2.this._2());
081          }
082        };
083      }
084    
085    
086      /**
087       * Split this product between two argument functions and combine their output.
088       *
089       * @param f A function that will map the first element of this product.
090       * @param g A function that will map the second element of this product.
091       * @return A new product with the first function applied to the second element
092       *         and the second function applied to the second element.
093       */
094      public <C, D> P2<C, D> split(final F<A, C> f, final F<B, D> g) {
095        final F<P2<A, D>, P2<C, D>> ff = map1_(f);
096        final F<P2<A, B>, P2<A, D>> gg = map2_(g);
097        return compose(ff, gg).f(this);
098      }
099    
100      /**
101       * Duplicates this product on the first element, and maps the given function across the duplicate (Comonad pattern).
102       *
103       * @param k A function to map over the duplicated product.
104       * @return A new product with the result of the given function applied to this product as the first element,
105       *         and with the second element intact.
106       */
107      public <C> P2<C, B> cobind(final F<P2<A, B>, C> k) {
108        return new P2<C, B>() {
109    
110          public C _1() {
111            return k.f(P2.this);
112          }
113    
114          public B _2() {
115            return P2.this._2();
116          }
117        };
118      }
119    
120      /**
121       * Duplicates this product into the first element (Comonad pattern).
122       *
123       * @return A new product with this product in its first element and with the second element intact.
124       */
125      public P2<P2<A, B>, B> duplicate() {
126        final F<P2<A, B>, P2<A, B>> id = identity();
127        return cobind(id);
128      }
129    
130      /**
131       * Replaces the first element of this product with the given value.
132       *
133       * @param c The value with which to replace the first element of this product.
134       * @return A new product with the first element replaced with the given value.
135       */
136      public <C> P2<C, B> inject(final C c) {
137        final F<P2<A, B>, C> co = constant(c);
138        return cobind(co);
139      }
140    
141      /**
142       * Applies a list of comonadic functions to this product, returning a list of values.
143       *
144       * @param fs A list of functions to apply to this product.
145       * @return A list of the results of applying the given list of functions to this product.
146       */
147      public <C> List<C> sequenceW(final List<F<P2<A, B>, C>> fs) {
148        List.Buffer<C> cs = List.Buffer.empty();
149        for (final F<P2<A, B>, C> f : fs)
150          cs = cs.snoc(f.f(this));
151        return cs.toList();
152      }
153    
154      /**
155       * Applies a stream of comonadic functions to this product, returning a stream of values.
156       *
157       * @param fs A stream of functions to apply to this product.
158       * @return A stream of the results of applying the given stream of functions to this product.
159       */
160      public <C> Stream<C> sequenceW(final Stream<F<P2<A, B>, C>> fs) {
161        return fs.isEmpty()
162               ? Stream.<C>nil()
163               : Stream.cons(fs.head().f(this), new P1<Stream<C>>() {
164                 public Stream<C> _1() {
165                   return sequenceW(fs.tail()._1());
166                 }
167               });
168      }
169    
170      /**
171       * Returns the 1-product projection over the first element.
172       *
173       * @return the 1-product projection over the first element.
174       */
175      public P1<A> _1_() {
176        return $(P2.<A, B>__1()).lazy().f(this);
177      }
178    
179      /**
180       * Returns the 1-product projection over the second element.
181       *
182       * @return the 1-product projection over the second element.
183       */
184      public P1<B> _2_() {
185        return $(P2.<A, B>__2()).lazy().f(this);
186      }
187    
188      /**
189       * Provides a memoising P2 that remembers its values.
190       *
191       * @return A P2 that calls this P2 once for any given element and remembers the value for subsequent calls.
192       */
193      public P2<A, B> memo() {
194        return new P2<A, B>() {
195          private final P1<A> a = _1_().memo();
196          private final P1<B> b = _2_().memo();
197    
198          public A _1() {
199            return a._1();
200          }
201    
202          public B _2() {
203            return b._1();
204          }
205        };
206      }
207    
208      /**
209       * A first-class version of the split function.
210       *
211       * @param f A function that will map the first element of the given product.
212       * @param g A function that will map the second element of the given product.
213       * @return A function that splits a given product between the two given functions and combines their output.
214       */
215      public static <A, B, C, D> F<P2<A, B>, P2<C, D>> split_(final F<A, C> f, final F<B, D> g) {
216        return new F<P2<A, B>, P2<C, D>>() {
217          public P2<C, D> f(final P2<A, B> p) {
218            return p.split(f, g);
219          }
220        };
221      }
222    
223      /**
224       * Promotes a function so that it maps the first element of a product.
225       *
226       * @param f The function to promote.
227       * @return The given function, promoted to map the first element of products.
228       */
229      public static <A, B, X> F<P2<A, B>, P2<X, B>> map1_(final F<A, X> f) {
230        return new F<P2<A, B>, P2<X, B>>() {
231          public P2<X, B> f(final P2<A, B> p) {
232            return p.map1(f);
233          }
234        };
235      }
236    
237      /**
238       * Promotes a function so that it maps the second element of a product.
239       *
240       * @param f The function to promote.
241       * @return The given function, promoted to map the second element of products.
242       */
243      public static <A, B, X> F<P2<A, B>, P2<A, X>> map2_(final F<B, X> f) {
244        return new F<P2<A, B>, P2<A, X>>() {
245          public P2<A, X> f(final P2<A, B> p) {
246            return p.map2(f);
247          }
248        };
249      }
250    
251      /**
252       * Sends the given input value to both argument functions and combines their output.
253       *
254       * @param f A function to receive an input value.
255       * @param g A function to receive an input value.
256       * @param b An input value to send to both functions.
257       * @return The product of the two functions applied to the input value.
258       */
259      public static <B, C, D> P2<C, D> fanout(final F<B, C> f, final F<B, D> g, final B b) {
260        return join(P.<B, B>p2()).f(b).split(f, g);
261      }
262    
263      /**
264       * Maps the given function across both the elements of the given product.
265       *
266       * @param f A function to map over a product.
267       * @param p A product over which to map.
268       * @return A new product with the given function applied to both elements.
269       */
270      public static <A, B> P2<B, B> map(final F<A, B> f, final P2<A, A> p) {
271        return p.split(f, f);
272      }
273    
274      /**
275       * Returns a curried form of {@link #swap()}.
276       *
277       * @return A curried form of {@link #swap()}.
278       */
279      public static <A, B> F<P2<A, B>, P2<B, A>> swap_() {
280        return new F<P2<A, B>, P2<B, A>>() {
281          public P2<B, A> f(final P2<A, B> p) {
282            return p.swap();
283          }
284        };
285      }
286    
287      /**
288       * Returns a function that returns the first element of a product.
289       *
290       * @return A function that returns the first element of a product.
291       */
292      public static <A, B> F<P2<A, B>, A> __1() {
293        return new F<P2<A, B>, A>() {
294          public A f(final P2<A, B> p) {
295            return p._1();
296          }
297        };
298      }
299    
300      /**
301       * Returns a function that returns the second element of a product.
302       *
303       * @return A function that returns the second element of a product.
304       */
305      public static <A, B> F<P2<A, B>, B> __2() {
306        return new F<P2<A, B>, B>() {
307          public B f(final P2<A, B> p) {
308            return p._2();
309          }
310        };
311      }
312    
313      /**
314       * Transforms a curried function of arity-2 to a function of a product-2
315       *
316       * @param f a curried function of arity-2 to transform into a function of a product-2
317       * @return The function, transformed to operate on on a product-2
318       */
319      public static <A, B, C> F<P2<A, B>, C> tuple(final F<A, F<B, C>> f) {
320        return new F<P2<A, B>, C>() {
321          public C f(final P2<A, B> p) {
322            return f.f(p._1()).f(p._2());
323          }
324        };
325      }
326    
327      /**
328       * Transforms an uncurried function of arity-2 to a function of a product-2
329       *
330       * @param f an uncurried function of arity-2 to transform into a function of a product-2
331       * @return The function, transformed to operate on on a product-2
332       */
333      public static <A, B, C> F<P2<A, B>, C> tuple(final F2<A, B, C> f) {
334        return tuple(curry(f));
335      }
336    
337      /**
338       * Transforms a function of a product-2 to an uncurried function or arity-2.
339       *
340       * @param f A function of a product-2 to transform into an uncurried function.
341       * @return The function, transformed to an uncurried function of arity-2.
342       */
343      public static <A, B, C> F2<A, B, C> untuple(final F<P2<A, B>, C> f) {
344        return new F2<A, B, C>() {
345          public C f(final A a, final B b) {
346            return f.f(P.p(a, b));
347          }
348        };
349      }
350    
351    }