001    package fj;
002    
003    import static fj.FW.$;
004    
005    /**
006     * A product-3.
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 P3<A, B, C> {
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       * Map the first element of the product.
038       *
039       * @param f The function to map with.
040       * @return A product with the given function applied.
041       */
042      public <X> P3<X, B, C> map1(final F<A, X> f) {
043        return new P3<X, B, C>() {
044          public X _1() {
045            return f.f(P3.this._1());
046          }
047    
048          public B _2() {
049            return P3.this._2();
050          }
051    
052          public C _3() {
053            return P3.this._3();
054          }
055        };
056      }
057    
058      /**
059       * Map the second element of the product.
060       *
061       * @param f The function to map with.
062       * @return A product with the given function applied.
063       */
064      public <X> P3<A, X, C> map2(final F<B, X> f) {
065        return new P3<A, X, C>() {
066          public A _1() {
067            return P3.this._1();
068          }
069    
070          public X _2() {
071            return f.f(P3.this._2());
072          }
073    
074          public C _3() {
075            return P3.this._3();
076          }
077        };
078      }
079    
080      /**
081       * Map the third element of the product.
082       *
083       * @param f The function to map with.
084       * @return A product with the given function applied.
085       */
086      public <X> P3<A, B, X> map3(final F<C, X> f) {
087        return new P3<A, B, X>() {
088          public A _1() {
089            return P3.this._1();
090          }
091    
092          public B _2() {
093            return P3.this._2();
094          }
095    
096          public X _3() {
097            return f.f(P3.this._3());
098          }
099        };
100      }
101    
102      /**
103       * Returns the 1-product projection over the first element.
104       *
105       * @return the 1-product projection over the first element.
106       */
107      public P1<A> _1_() {
108        return $(P3.<A, B, C>__1()).lazy().f(this);
109      }
110    
111      /**
112       * Returns the 1-product projection over the second element.
113       *
114       * @return the 1-product projection over the second element.
115       */
116      public P1<B> _2_() {
117        return $(P3.<A, B, C>__2()).lazy().f(this);
118      }
119    
120      /**
121       * Returns the 1-product projection over the third element.
122       *
123       * @return the 1-product projection over the third element.
124       */
125      public P1<C> _3_() {
126        return $(P3.<A, B, C>__3()).lazy().f(this);
127      }
128    
129      /**
130       * Provides a memoising P3 that remembers its values.
131       *
132       * @return A P3 that calls this P3 once for any given element and remembers the value for subsequent calls.
133       */
134      public P3<A, B, C> memo() {
135        return new P3<A, B, C>() {
136          private final P1<A> a = _1_().memo();
137          private final P1<B> b = _2_().memo();
138          private final P1<C> c = _3_().memo();
139    
140          public A _1() {
141            return a._1();
142          }
143    
144          public B _2() {
145            return b._1();
146          }
147    
148          public C _3() {
149            return c._1();
150          }
151        };
152      }
153    
154      /**
155       * Returns a function that returns the first element of a product.
156       *
157       * @return A function that returns the first element of a product.
158       */
159      public static <A, B, C> F<P3<A, B, C>, A> __1() {
160        return new F<P3<A, B, C>, A>() {
161          public A f(final P3<A, B, C> p) {
162            return p._1();
163          }
164        };
165      }
166    
167      /**
168       * Returns a function that returns the second element of a product.
169       *
170       * @return A function that returns the second element of a product.
171       */
172      public static <A, B, C> F<P3<A, B, C>, B> __2() {
173        return new F<P3<A, B, C>, B>() {
174          public B f(final P3<A, B, C> p) {
175            return p._2();
176          }
177        };
178      }
179    
180      /**
181       * Returns a function that returns the third element of a product.
182       *
183       * @return A function that returns the third element of a product.
184       */
185      public static <A, B, C> F<P3<A, B, C>, C> __3() {
186        return new F<P3<A, B, C>, C>() {
187          public C f(final P3<A, B, C> p) {
188            return p._3();
189          }
190        };
191      }
192    }