001    package fj;
002    
003    import static fj.FW.$;
004    
005    /**
006     * A product-4.
007     *
008     * @version %build.number%<br>
009     *          <ul>
010     *          <li>$LastChangedRevision: 270 $</li>
011     *          <li>$LastChangedDate: 2009-07-28 14:06:27 +1000 (Tue, 28 Jul 2009) $</li>
012     *          </ul>
013     */
014    public abstract class P4<A, B, C, D> {
015      /**
016       * Access the first element of the product.
017       *
018       * @return The first element of the product.
019       */
020      public abstract A _1();
021    
022      /**
023       * Access the second element of the product.
024       *
025       * @return The second element of the product.
026       */
027      public abstract B _2();
028    
029      /**
030       * Access the third element of the product.
031       *
032       * @return The third element of the product.
033       */
034      public abstract C _3();
035    
036      /**
037       * Access the fourth element of the product.
038       *
039       * @return The fourth element of the product.
040       */
041      public abstract D _4();
042    
043      /**
044       * Map the first element of the product.
045       *
046       * @param f The function to map with.
047       * @return A product with the given function applied.
048       */
049      public <X> P4<X, B, C, D> map1(final F<A, X> f) {
050        return new P4<X, B, C, D>() {
051          public X _1() {
052            return f.f(P4.this._1());
053          }
054    
055          public B _2() {
056            return P4.this._2();
057          }
058    
059          public C _3() {
060            return P4.this._3();
061          }
062    
063          public D _4() {
064            return P4.this._4();
065          }
066        };
067      }
068    
069      /**
070       * Map the second element of the product.
071       *
072       * @param f The function to map with.
073       * @return A product with the given function applied.
074       */
075      public <X> P4<A, X, C, D> map2(final F<B, X> f) {
076        return new P4<A, X, C, D>() {
077          public A _1() {
078            return P4.this._1();
079          }
080    
081          public X _2() {
082            return f.f(P4.this._2());
083          }
084    
085          public C _3() {
086            return P4.this._3();
087          }
088    
089          public D _4() {
090            return P4.this._4();
091          }
092        };
093      }
094    
095      /**
096       * Map the third element of the product.
097       *
098       * @param f The function to map with.
099       * @return A product with the given function applied.
100       */
101      public <X> P4<A, B, X, D> map3(final F<C, X> f) {
102        return new P4<A, B, X, D>() {
103          public A _1() {
104            return P4.this._1();
105          }
106    
107          public B _2() {
108            return P4.this._2();
109          }
110    
111          public X _3() {
112            return f.f(P4.this._3());
113          }
114    
115          public D _4() {
116            return P4.this._4();
117          }
118        };
119      }
120    
121      /**
122       * Map the fourth element of the product.
123       *
124       * @param f The function to map with.
125       * @return A product with the given function applied.
126       */
127      public <X> P4<A, B, C, X> map4(final F<D, X> f) {
128        return new P4<A, B, C, X>() {
129          public A _1() {
130            return P4.this._1();
131          }
132    
133          public B _2() {
134            return P4.this._2();
135          }
136    
137          public C _3() {
138            return P4.this._3();
139          }
140    
141          public X _4() {
142            return f.f(P4.this._4());
143          }
144        };
145      }
146    
147      /**
148       * Returns the 1-product projection over the first element.
149       *
150       * @return the 1-product projection over the first element.
151       */
152      public P1<A> _1_() {
153        return $(P4.<A, B, C, D>__1()).lazy().f(this);
154      }
155    
156      /**
157       * Returns the 1-product projection over the second element.
158       *
159       * @return the 1-product projection over the second element.
160       */
161      public P1<B> _2_() {
162        return $(P4.<A, B, C, D>__2()).lazy().f(this);
163      }
164    
165      /**
166       * Returns the 1-product projection over the third element.
167       *
168       * @return the 1-product projection over the third element.
169       */
170      public P1<C> _3_() {
171        return $(P4.<A, B, C, D>__3()).lazy().f(this);
172      }
173    
174      /**
175       * Returns the 1-product projection over the fourth element.
176       *
177       * @return the 1-product projection over the fourth element.
178       */
179      public P1<D> _4_() {
180        return $(P4.<A, B, C, D>__4()).lazy().f(this);
181      }
182    
183      /**
184       * Provides a memoising P4 that remembers its values.
185       *
186       * @return A P4 that calls this P4 once for any given element and remembers the value for subsequent calls.
187       */
188      public P4<A, B, C, D> memo() {
189        return new P4<A, B, C, D>() {
190          private final P1<A> a = _1_().memo();
191          private final P1<B> b = _2_().memo();
192          private final P1<C> c = _3_().memo();
193          private final P1<D> d = _4_().memo();
194    
195          public A _1() {
196            return a._1();
197          }
198    
199          public B _2() {
200            return b._1();
201          }
202    
203          public C _3() {
204            return c._1();
205          }
206    
207          public D _4() {
208            return d._1();
209          }
210        };
211      }
212    
213    
214      /**
215       * Returns a function that returns the first element of a product.
216       *
217       * @return A function that returns the first element of a product.
218       */
219      public static <A, B, C, D> F<P4<A, B, C, D>, A> __1() {
220        return new F<P4<A, B, C, D>, A>() {
221          public A f(final P4<A, B, C, D> p) {
222            return p._1();
223          }
224        };
225      }
226    
227      /**
228       * Returns a function that returns the second element of a product.
229       *
230       * @return A function that returns the second element of a product.
231       */
232      public static <A, B, C, D> F<P4<A, B, C, D>, B> __2() {
233        return new F<P4<A, B, C, D>, B>() {
234          public B f(final P4<A, B, C, D> p) {
235            return p._2();
236          }
237        };
238      }
239    
240      /**
241       * Returns a function that returns the third element of a product.
242       *
243       * @return A function that returns the third element of a product.
244       */
245      public static <A, B, C, D> F<P4<A, B, C, D>, C> __3() {
246        return new F<P4<A, B, C, D>, C>() {
247          public C f(final P4<A, B, C, D> p) {
248            return p._3();
249          }
250        };
251      }
252    
253      /**
254       * Returns a function that returns the fourth element of a product.
255       *
256       * @return A function that returns the fourth element of a product.
257       */
258      public static <A, B, C, D> F<P4<A, B, C, D>, D> __4() {
259        return new F<P4<A, B, C, D>, D>() {
260          public D f(final P4<A, B, C, D> p) {
261            return p._4();
262          }
263        };
264      }
265    }