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 }