001    package fj;
002    
003    /**
004     * Transformations on functions.
005     *
006     * @version %build.number%<br>
007     *          <ul>
008     *          <li>$LastChangedRevision: 173 $</li>
009     *          <li>$LastChangedDate: 2009-06-19 16:01:56 +1000 (Fri, 19 Jun 2009) $</li>
010     *          </ul>
011     */
012    public final class Function {
013      private Function() {
014        throw new UnsupportedOperationException();
015      }
016    
017      /**
018       * Function composition.
019       *
020       * @return A function that composes two functions to produce a new function.
021       */
022      public static <A, B, C> F<F<B, C>, F<F<A, B>, F<A, C>>> compose() {
023        return new F<F<B, C>, F<F<A, B>, F<A, C>>>() {
024          public F<F<A, B>, F<A, C>> f(final F<B, C> f) {
025            return new F<F<A, B>, F<A, C>>() {
026              public F<A, C> f(final F<A, B> g) {
027                return compose(f, g);
028              }
029            };
030          }
031        };
032      }
033    
034      /**
035       * Function composition.
036       *
037       * @param f A function to compose with another.
038       * @param g A function to compose with another.
039       * @return A function that is the composition of the given arguments.
040       */
041      public static <A, B, C> F<A, C> compose(final F<B, C> f, final F<A, B> g) {
042        return new F<A, C>() {
043          public C f(final A a) {
044            return f.f(g.f(a));
045          }
046        };
047      }
048    
049      /**
050       * Function composition.
051       *
052       * @param f A function to compose with another.
053       * @param g A function to compose with another.
054       * @return A function that is the composition of the given arguments.
055       */
056      public static <A, B, C, D> F<A, F<B, D>> compose2(final F<C, D> f, final F<A, F<B, C>> g) {
057        return new F<A, F<B, D>>() {
058          public F<B, D> f(final A a) {
059            return new F<B, D>() {
060              public D f(final B b) {
061                return f.f(g.f(a).f(b));
062              }
063            };
064          }
065        };
066      }
067    
068    
069      /**
070       * Function composition flipped.
071       *
072       * @return A function that composes two functions to produce a new function.
073       */
074      public static <A, B, C> F<F<A, B>, F<F<B, C>, F<A, C>>> andThen() {
075        return new F<F<A, B>, F<F<B, C>, F<A, C>>>() {
076          public F<F<B, C>, F<A, C>> f(final F<A, B> g) {
077            return new F<F<B, C>, F<A, C>>() {
078              public F<A, C> f(final F<B, C> f) {
079                return andThen(g, f);
080              }
081            };
082          }
083        };
084      }
085    
086      /**
087       * Function composition flipped.
088       *
089       * @param g A function to compose with another.
090       * @param f A function to compose with another.
091       * @return A function that is the composition of the given arguments.
092       */
093      public static <A, B, C> F<A, C> andThen(final F<A, B> g, final F<B, C> f) {
094        return new F<A, C>() {
095          public C f(final A a) {
096            return f.f(g.f(a));
097          }
098        };
099      }
100    
101      /**
102       * The identity transformation.
103       *
104       * @return The identity transformation.
105       */
106      public static <A> F<A, A> identity() {
107        return new F<A, A>() {
108          public A f(final A a) {
109            return a;
110          }
111        };
112      }
113    
114      /**
115       * Returns a function that given an argument, returns a function that ignores its argument.
116       *
117       * @return A function that given an argument, returns a function that ignores its argument.
118       */
119      public static <A, B> F<B, F<A, B>> constant() {
120        return new F<B, F<A, B>>() {
121          public F<A, B> f(final B b) {
122            return constant(b);
123          }
124        };
125      }
126    
127      /**
128       * Returns a function that ignores its argument to constantly produce the given value.
129       *
130       * @param b The value to return when the returned function is applied.
131       * @return A function that ignores its argument to constantly produce the given value.
132       */
133      public static <A, B> F<A, B> constant(final B b) {
134        return new F<A, B>() {
135          public B f(final A a) {
136            return b;
137          }
138        };
139      }
140    
141      /**
142       * Simultaneously covaries and contravaries a function.
143       *
144       * @param f The function to vary.
145       * @return A co- and contravariant function that invokes f on its argument.
146       */
147      public static <A, B> F<A, B> vary(final F<? super A, ? extends B> f) {
148        return new F<A, B>() {
149          public B f(final A a) {
150            return f.f(a);
151          }
152        };
153      }
154    
155      /**
156       * Simultaneously covaries and contravaries a function.
157       *
158       * @return A function that varies and covaries a function.
159       */
160      public static <C, A extends C, B, D extends B> F<F<C, D>, F<A, B>> vary() {
161        return new F<F<C, D>, F<A, B>>() {
162          public F<A, B> f(final F<C, D> f) {
163            return Function.<A, B>vary(f);
164          }
165        };
166      }
167    
168      /**
169       * Function argument flipping.
170       *
171       * @return A function that takes a function and flips its arguments.
172       */
173      public static <A, B, C> F<F<A, F<B, C>>, F<B, F<A, C>>> flip() {
174        return new F<F<A, F<B, C>>, F<B, F<A, C>>>() {
175          public F<B, F<A, C>> f(final F<A, F<B, C>> f) {
176            return flip(f);
177          }
178        };
179      }
180    
181      /**
182       * Function argument flipping.
183       *
184       * @param f The function to flip.
185       * @return The given function flipped.
186       */
187      public static <A, B, C> F<B, F<A, C>> flip(final F<A, F<B, C>> f) {
188        return new F<B, F<A, C>>() {
189          public F<A, C> f(final B b) {
190            return new F<A, C>() {
191              public C f(final A a) {
192                return f.f(a).f(b);
193              }
194            };
195          }
196        };
197      }
198    
199      /**
200       * Function argument flipping.
201       *
202       * @param f The function to flip.
203       * @return The given function flipped.
204       */
205      public static <A, B, C> F2<B, A, C> flip(final F2<A, B, C> f) {
206        return new F2<B, A, C>() {
207          public C f(final B b, final A a) {
208            return f.f(a, b);
209          }
210        };
211      }
212    
213      /**
214       * Function argument flipping.
215       *
216       * @return A function that flips the arguments of a given function.
217       */
218      public static <A, B, C> F<F2<A, B, C>, F2<B, A, C>> flip2() {
219        return new F<F2<A, B, C>, F2<B, A, C>>() {
220          public F2<B, A, C> f(final F2<A, B, C> f) {
221            return flip(f);
222          }
223        };
224      }
225    
226      /**
227       * Curry a function of arity-2.
228       *
229       * @param f The function to curry.
230       * @return A curried form of the given function.
231       */
232      public static <A, B, C> F<A, F<B, C>> curry(final F2<A, B, C> f) {
233        return new F<A, F<B, C>>() {
234          public F<B, C> f(final A a) {
235            return new F<B, C>() {
236              public C f(final B b) {
237                return f.f(a, b);
238              }
239            };
240          }
241        };
242      }
243    
244      /**
245       * Curry a function of arity-2.
246       *
247       * @param f The function to curry.
248       * @param a An argument to the curried function.
249       * @return A curried form of the given function.
250       */
251      public static <A, B, C> F<B, C> curry(final F2<A, B, C> f, final A a) {
252        return curry(f).f(a);
253      }
254    
255      /**
256       * Uncurry a function of arity-2.
257       *
258       * @return An uncurried function.
259       */
260      public static <A, B, C> F<F<A, F<B, C>>, F2<A, B, C>> uncurryF2() {
261        return new F<F<A, F<B, C>>, F2<A, B, C>>() {
262          public F2<A, B, C> f(final F<A, F<B, C>> f) {
263            return uncurryF2(f);
264          }
265        };
266      }
267    
268      /**
269       * Uncurry a function of arity-2.
270       *
271       * @param f The function to uncurry.
272       * @return An uncurried function.
273       */
274      public static <A, B, C> F2<A, B, C> uncurryF2(final F<A, F<B, C>> f) {
275        return new F2<A, B, C>() {
276          public C f(final A a, final B b) {
277            return f.f(a).f(b);
278          }
279        };
280      }
281    
282      /**
283       * Curry a function of arity-3.
284       *
285       * @param f The function to curry.
286       * @return A curried form of the given function.
287       */
288      public static <A, B, C, D> F<A, F<B, F<C, D>>> curry(final F3<A, B, C, D> f) {
289        return new F<A, F<B, F<C, D>>>() {
290          public F<B, F<C, D>> f(final A a) {
291            return new F<B, F<C, D>>() {
292              public F<C, D> f(final B b) {
293                return new F<C, D>() {
294                  public D f(final C c) {
295                    return f.f(a, b, c);
296                  }
297                };
298              }
299            };
300          }
301        };
302      }
303    
304      /**
305       * Curry a function of arity-3.
306       *
307       * @param f The function to curry.
308       * @param a An argument to the curried function.
309       * @return A curried form of the given function.
310       */
311      public static <A, B, C, D> F<B, F<C, D>> curry(final F3<A, B, C, D> f, final A a) {
312        return curry(f).f(a);
313      }
314    
315      /**
316       * Curry a function of arity-3.
317       *
318       * @param f The function to curry.
319       * @param a An argument to the curried function.
320       * @param b An argument to the curried function.
321       * @return A curried form of the given function.
322       */
323      public static <A, B, C, D> F<C, D> curry(final F3<A, B, C, D> f, final A a, final B b) {
324        return curry(f, a).f(b);
325      }
326    
327      /**
328       * Uncurry a function of arity-3.
329       *
330       * @return An uncurried function.
331       */
332      public static <A, B, C, D> F<F<A, F<B, F<C, D>>>, F3<A, B, C, D>> uncurryF3() {
333        return new F<F<A, F<B, F<C, D>>>, F3<A, B, C, D>>() {
334          public F3<A, B, C, D> f(final F<A, F<B, F<C, D>>> f) {
335            return uncurryF3(f);
336          }
337        };
338      }
339    
340      /**
341       * Uncurry a function of arity-3.
342       *
343       * @param f The function to uncurry.
344       * @return An uncurried function.
345       */
346      public static <A, B, C, D> F3<A, B, C, D> uncurryF3(final F<A, F<B, F<C, D>>> f) {
347        return new F3<A, B, C, D>() {
348          public D f(final A a, final B b, final C c) {
349            return f.f(a).f(b).f(c);
350          }
351        };
352      }
353    
354      /**
355       * Curry a function of arity-4.
356       *
357       * @param f The function to curry.
358       * @return A curried form of the given function.
359       */
360      public static <A, B, C, D, E> F<A, F<B, F<C, F<D, E>>>> curry(final F4<A, B, C, D, E> f) {
361        return new F<A, F<B, F<C, F<D, E>>>>() {
362          public F<B, F<C, F<D, E>>> f(final A a) {
363            return new F<B, F<C, F<D, E>>>() {
364              public F<C, F<D, E>> f(final B b) {
365                return new F<C, F<D, E>>() {
366                  public F<D, E> f(final C c) {
367                    return new F<D, E>() {
368                      public E f(final D d) {
369                        return f.f(a, b, c, d);
370                      }
371                    };
372                  }
373                };
374              }
375            };
376          }
377        };
378      }
379    
380      /**
381       * Curry a function of arity-4.
382       *
383       * @param f The function to curry.
384       * @param a An argument to the curried function.
385       * @return A curried form of the given function.
386       */
387      public static <A, B, C, D, E> F<B, F<C, F<D, E>>> curry(final F4<A, B, C, D, E> f, final A a) {
388        return curry(f).f(a);
389      }
390    
391      /**
392       * Curry a function of arity-4.
393       *
394       * @param f The function to curry.
395       * @param a An argument to the curried function.
396       * @param b An argument to the curried function.
397       * @return A curried form of the given function.
398       */
399      public static <A, B, C, D, E> F<C, F<D, E>> curry(final F4<A, B, C, D, E> f, final A a, final B b) {
400        return curry(f).f(a).f(b);
401      }
402    
403      /**
404       * Curry a function of arity-4.
405       *
406       * @param f The function to curry.
407       * @param a An argument to the curried function.
408       * @param b An argument to the curried function.
409       * @param c An argument to the curried function.
410       * @return A curried form of the given function.
411       */
412      public static <A, B, C, D, E> F<D, E> curry(final F4<A, B, C, D, E> f, final A a, final B b, final C c) {
413        return curry(f).f(a).f(b).f(c);
414      }
415    
416      /**
417       * Uncurry a function of arity-4.
418       *
419       * @return An uncurried function.
420       */
421      public static <A, B, C, D, E> F<F<A, F<B, F<C, F<D, E>>>>, F4<A, B, C, D, E>> uncurryF4() {
422        return new F<F<A, F<B, F<C, F<D, E>>>>, F4<A, B, C, D, E>>() {
423          public F4<A, B, C, D, E> f(final F<A, F<B, F<C, F<D, E>>>> f) {
424            return uncurryF4(f);
425          }
426        };
427      }
428    
429      /**
430       * Uncurry a function of arity-4.
431       *
432       * @param f The function to uncurry.
433       * @return An uncurried function.
434       */
435      public static <A, B, C, D, E> F4<A, B, C, D, E> uncurryF4(final F<A, F<B, F<C, F<D, E>>>> f) {
436        return new F4<A, B, C, D, E>() {
437          public E f(final A a, final B b, final C c, final D d) {
438            return f.f(a).f(b).f(c).f(d);
439          }
440        };
441      }
442    
443      /**
444       * Curry a function of arity-5.
445       *
446       * @param f The function to curry.
447       * @return A curried form of the given function.
448       */
449      public static <A, B, C, D, E, F$> F<A, F<B, F<C, F<D, F<E, F$>>>>> curry(final F5<A, B, C, D, E, F$> f) {
450        return new F<A, F<B, F<C, F<D, F<E, F$>>>>>() {
451          public F<B, F<C, F<D, F<E, F$>>>> f(final A a) {
452            return new F<B, F<C, F<D, F<E, F$>>>>() {
453              public F<C, F<D, F<E, F$>>> f(final B b) {
454                return new F<C, F<D, F<E, F$>>>() {
455                  public F<D, F<E, F$>> f(final C c) {
456                    return new F<D, F<E, F$>>() {
457                      public F<E, F$> f(final D d) {
458                        return new F<E, F$>() {
459                          public F$ f(final E e) {
460                            return f.f(a, b, c, d, e);
461                          }
462                        };
463                      }
464                    };
465                  }
466                };
467              }
468            };
469          }
470        };
471      }
472    
473      /**
474       * Curry a function of arity-5.
475       *
476       * @param f The function to curry.
477       * @param a An argument to the curried function.
478       * @return A curried form of the given function.
479       */
480      public static <A, B, C, D, E, F$> F<B, F<C, F<D, F<E, F$>>>> curry(final F5<A, B, C, D, E, F$> f, final A a) {
481        return curry(f).f(a);
482      }
483    
484      /**
485       * Curry a function of arity-5.
486       *
487       * @param f The function to curry.
488       * @param a An argument to the curried function.
489       * @param b An argument to the curried function.
490       * @return A curried form of the given function.
491       */
492      public static <A, B, C, D, E, F$> F<C, F<D, F<E, F$>>> curry(final F5<A, B, C, D, E, F$> f, final A a, final B b) {
493        return curry(f).f(a).f(b);
494      }
495    
496      /**
497       * Curry a function of arity-5.
498       *
499       * @param f The function to curry.
500       * @param a An argument to the curried function.
501       * @param b An argument to the curried function.
502       * @param c An argument to the curried function.
503       * @return A curried form of the given function.
504       */
505      public static <A, B, C, D, E, F$> F<D, F<E, F$>> curry(final F5<A, B, C, D, E, F$> f, final A a, final B b,
506                                                             final C c) {
507        return curry(f).f(a).f(b).f(c);
508      }
509    
510      /**
511       * Curry a function of arity-5.
512       *
513       * @param f The function to curry.
514       * @param a An argument to the curried function.
515       * @param b An argument to the curried function.
516       * @param c An argument to the curried function.
517       * @param d An argument to the curried function.
518       * @return A curried form of the given function.
519       */
520      public static <A, B, C, D, E, F$> F<E, F$> curry(final F5<A, B, C, D, E, F$> f, final A a, final B b, final C c,
521                                                       final D d) {
522        return curry(f).f(a).f(b).f(c).f(d);
523      }
524    
525      /**
526       * Uncurry a function of arity-5.
527       *
528       * @return An uncurried function.
529       */
530      public static <A, B, C, D, E, F$> F<F<A, F<B, F<C, F<D, F<E, F$>>>>>, F5<A, B, C, D, E, F$>> uncurryF5() {
531        return new F<F<A, F<B, F<C, F<D, F<E, F$>>>>>, F5<A, B, C, D, E, F$>>() {
532          public F5<A, B, C, D, E, F$> f(final F<A, F<B, F<C, F<D, F<E, F$>>>>> f) {
533            return uncurryF5(f);
534          }
535        };
536      }
537    
538      /**
539       * Uncurry a function of arity-6.
540       *
541       * @param f The function to uncurry.
542       * @return An uncurried function.
543       */
544      public static <A, B, C, D, E, F$> F5<A, B, C, D, E, F$> uncurryF5(final F<A, F<B, F<C, F<D, F<E, F$>>>>> f) {
545        return new F5<A, B, C, D, E, F$>() {
546          public F$ f(final A a, final B b, final C c, final D d, final E e) {
547            return f.f(a).f(b).f(c).f(d).f(e);
548          }
549        };
550      }
551    
552      /**
553       * Curry a function of arity-6.
554       *
555       * @param f The function to curry.
556       * @return A curried form of the given function.
557       */
558      public static <A, B, C, D, E, F$, G> F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>> curry(final F6<A, B, C, D, E, F$, G> f) {
559        return new F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>>() {
560          public F<B, F<C, F<D, F<E, F<F$, G>>>>> f(final A a) {
561            return new F<B, F<C, F<D, F<E, F<F$, G>>>>>() {
562              public F<C, F<D, F<E, F<F$, G>>>> f(final B b) {
563                return new F<C, F<D, F<E, F<F$, G>>>>() {
564                  public F<D, F<E, F<F$, G>>> f(final C c) {
565                    return new F<D, F<E, F<F$, G>>>() {
566                      public F<E, F<F$, G>> f(final D d) {
567                        return new F<E, F<F$, G>>() {
568                          public F<F$, G> f(final E e) {
569                            return new F<F$, G>() {
570                              public G f(final F$ f$) {
571                                return f.f(a, b, c, d, e, f$);
572                              }
573                            };
574                          }
575                        };
576                      }
577                    };
578                  }
579                };
580              }
581            };
582          }
583        };
584      }
585    
586      /**
587       * Uncurry a function of arity-6.
588       *
589       * @return An uncurried function.
590       */
591      public static <A, B, C, D, E, F$, G> F<F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>>, F6<A, B, C, D, E, F$, G>> uncurryF6() {
592        return new F<F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>>, F6<A, B, C, D, E, F$, G>>() {
593          public F6<A, B, C, D, E, F$, G> f(final F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>> f) {
594            return uncurryF6(f);
595          }
596        };
597      }
598    
599      /**
600       * Uncurry a function of arity-6.
601       *
602       * @param f The function to uncurry.
603       * @return An uncurried function.
604       */
605      public static <A, B, C, D, E, F$, G> F6<A, B, C, D, E, F$, G> uncurryF6(
606          final F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>> f) {
607        return new F6<A, B, C, D, E, F$, G>() {
608          public G f(final A a, final B b, final C c, final D d, final E e, final F$ f$) {
609            return f.f(a).f(b).f(c).f(d).f(e).f(f$);
610          }
611        };
612      }
613    
614      /**
615       * Curry a function of arity-7.
616       *
617       * @param f The function to curry.
618       * @return A curried form of the given function.
619       */
620      public static <A, B, C, D, E, F$, G, H> F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>> curry(
621          final F7<A, B, C, D, E, F$, G, H> f) {
622        return new F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>>() {
623          public F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>> f(final A a) {
624            return new F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>() {
625              public F<C, F<D, F<E, F<F$, F<G, H>>>>> f(final B b) {
626                return new F<C, F<D, F<E, F<F$, F<G, H>>>>>() {
627                  public F<D, F<E, F<F$, F<G, H>>>> f(final C c) {
628                    return new F<D, F<E, F<F$, F<G, H>>>>() {
629                      public F<E, F<F$, F<G, H>>> f(final D d) {
630                        return new F<E, F<F$, F<G, H>>>() {
631                          public F<F$, F<G, H>> f(final E e) {
632                            return new F<F$, F<G, H>>() {
633                              public F<G, H> f(final F$ f$) {
634                                return new F<G, H>() {
635                                  public H f(final G g) {
636                                    return f.f(a, b, c, d, e, f$, g);
637                                  }
638                                };
639                              }
640                            };
641                          }
642                        };
643                      }
644                    };
645                  }
646                };
647              }
648            };
649          }
650        };
651      }
652    
653      /**
654       * Curry a function of arity-7.
655       *
656       * @param f The function to curry.
657       * @param a An argument to the curried function.
658       * @return A curried form of the given function.
659       */
660      public static <A, B, C, D, E, F$, G, H> F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>> curry(
661          final F7<A, B, C, D, E, F$, G, H> f, final A a) {
662        return curry(f).f(a);
663      }
664    
665      /**
666       * Curry a function of arity-7.
667       *
668       * @param f The function to curry.
669       * @param a An argument to the curried function.
670       * @param b An argument to the curried function.
671       * @return A curried form of the given function.
672       */
673      public static <A, B, C, D, E, F$, G, H> F<C, F<D, F<E, F<F$, F<G, H>>>>> curry(final F7<A, B, C, D, E, F$, G, H> f,
674                                                                                     final A a, final B b) {
675        return curry(f).f(a).f(b);
676      }
677    
678      /**
679       * Curry a function of arity-7.
680       *
681       * @param f The function to curry.
682       * @param a An argument to the curried function.
683       * @param b An argument to the curried function.
684       * @param c An argument to the curried function.
685       * @return A curried form of the given function.
686       */
687      public static <A, B, C, D, E, F$, G, H> F<D, F<E, F<F$, F<G, H>>>> curry(final F7<A, B, C, D, E, F$, G, H> f,
688                                                                               final A a, final B b, final C c) {
689        return curry(f).f(a).f(b).f(c);
690      }
691    
692      /**
693       * Curry a function of arity-7.
694       *
695       * @param f The function to curry.
696       * @param a An argument to the curried function.
697       * @param b An argument to the curried function.
698       * @param c An argument to the curried function.
699       * @param d An argument to the curried function.
700       * @return A curried form of the given function.
701       */
702      public static <A, B, C, D, E, F$, G, H> F<E, F<F$, F<G, H>>> curry(final F7<A, B, C, D, E, F$, G, H> f, final A a,
703                                                                         final B b, final C c, final D d) {
704        return curry(f).f(a).f(b).f(c).f(d);
705      }
706    
707      /**
708       * Curry a function of arity-7.
709       *
710       * @param f The function to curry.
711       * @param a An argument to the curried function.
712       * @param b An argument to the curried function.
713       * @param c An argument to the curried function.
714       * @param d An argument to the curried function.
715       * @param e An argument to the curried function.
716       * @return A curried form of the given function.
717       */
718      public static <A, B, C, D, E, F$, G, H> F<F$, F<G, H>> curry(final F7<A, B, C, D, E, F$, G, H> f, final A a,
719                                                                   final B b, final C c, final D d, final E e) {
720        return curry(f).f(a).f(b).f(c).f(d).f(e);
721      }
722    
723      /**
724       * Curry a function of arity-7.
725       *
726       * @param f  The function to curry.
727       * @param a  An argument to the curried function.
728       * @param b  An argument to the curried function.
729       * @param c  An argument to the curried function.
730       * @param d  An argument to the curried function.
731       * @param e  An argument to the curried function.
732       * @param f$ An argument to the curried function.
733       * @return A curried form of the given function.
734       */
735      public static <A, B, C, D, E, F$, G, H> F<G, H> curry(final F7<A, B, C, D, E, F$, G, H> f, final A a, final B b,
736                                                            final C c, final D d, final E e, final F$ f$) {
737        return curry(f).f(a).f(b).f(c).f(d).f(e).f(f$);
738      }
739    
740      /**
741       * Uncurry a function of arity-7.
742       *
743       * @return An uncurried function.
744       */
745      public static <A, B, C, D, E, F$, G, H> F<F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>>, F7<A, B, C, D, E, F$, G, H>> uncurryF7() {
746        return new F<F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>>, F7<A, B, C, D, E, F$, G, H>>() {
747          public F7<A, B, C, D, E, F$, G, H> f(final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>> f) {
748            return uncurryF7(f);
749          }
750        };
751      }
752    
753      /**
754       * Uncurry a function of arity-7.
755       *
756       * @param f The function to uncurry.
757       * @return An uncurried function.
758       */
759      public static <A, B, C, D, E, F$, G, H> F7<A, B, C, D, E, F$, G, H> uncurryF7(
760          final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>> f) {
761        return new F7<A, B, C, D, E, F$, G, H>() {
762          public H f(final A a, final B b, final C c, final D d, final E e, final F$ f$, final G g) {
763            return f.f(a).f(b).f(c).f(d).f(e).f(f$).f(g);
764          }
765        };
766      }
767    
768      /**
769       * Curry a function of arity-8.
770       *
771       * @param f The function to curry.
772       * @return A curried form of the given function.
773       */
774      public static <A, B, C, D, E, F$, G, H, I> F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>> curry(
775          final F8<A, B, C, D, E, F$, G, H, I> f) {
776        return new F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>>() {
777          public F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>> f(final A a) {
778            return new F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>() {
779              public F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>> f(final B b) {
780                return new F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>() {
781                  public F<D, F<E, F<F$, F<G, F<H, I>>>>> f(final C c) {
782                    return new F<D, F<E, F<F$, F<G, F<H, I>>>>>() {
783                      public F<E, F<F$, F<G, F<H, I>>>> f(final D d) {
784                        return new F<E, F<F$, F<G, F<H, I>>>>() {
785                          public F<F$, F<G, F<H, I>>> f(final E e) {
786                            return new F<F$, F<G, F<H, I>>>() {
787                              public F<G, F<H, I>> f(final F$ f$) {
788                                return new F<G, F<H, I>>() {
789                                  public F<H, I> f(final G g) {
790                                    return new F<H, I>() {
791                                      public I f(final H h) {
792                                        return f.f(a, b, c, d, e, f$, g, h);
793                                      }
794                                    };
795                                  }
796                                };
797                              }
798                            };
799                          }
800                        };
801                      }
802                    };
803                  }
804                };
805              }
806            };
807          }
808        };
809      }
810    
811      /**
812       * Curry a function of arity-8.
813       *
814       * @param f The function to curry.
815       * @param a An argument to the curried function.
816       * @return A curried form of the given function.
817       */
818      public static <A, B, C, D, E, F$, G, H, I> F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>> curry(
819          final F8<A, B, C, D, E, F$, G, H, I> f, final A a) {
820        return curry(f).f(a);
821      }
822    
823      /**
824       * Curry a function of arity-8.
825       *
826       * @param f The function to curry.
827       * @param a An argument to the curried function.
828       * @param b An argument to the curried function.
829       * @return A curried form of the given function.
830       */
831      public static <A, B, C, D, E, F$, G, H, I> F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>> curry(
832          final F8<A, B, C, D, E, F$, G, H, I> f, final A a, final B b) {
833        return curry(f).f(a).f(b);
834      }
835    
836      /**
837       * Curry a function of arity-8.
838       *
839       * @param f The function to curry.
840       * @param a An argument to the curried function.
841       * @param b An argument to the curried function.
842       * @param c An argument to the curried function.
843       * @return A curried form of the given function.
844       */
845      public static <A, B, C, D, E, F$, G, H, I> F<D, F<E, F<F$, F<G, F<H, I>>>>> curry(
846          final F8<A, B, C, D, E, F$, G, H, I> f, final A a, final B b, final C c) {
847        return curry(f).f(a).f(b).f(c);
848      }
849    
850      /**
851       * Curry a function of arity-8.
852       *
853       * @param f The function to curry.
854       * @param a An argument to the curried function.
855       * @param b An argument to the curried function.
856       * @param c An argument to the curried function.
857       * @param d An argument to the curried function.
858       * @return A curried form of the given function.
859       */
860      public static <A, B, C, D, E, F$, G, H, I> F<E, F<F$, F<G, F<H, I>>>> curry(final F8<A, B, C, D, E, F$, G, H, I> f,
861                                                                                  final A a, final B b, final C c,
862                                                                                  final D d) {
863        return curry(f).f(a).f(b).f(c).f(d);
864      }
865    
866      /**
867       * Curry a function of arity-8.
868       *
869       * @param f The function to curry.
870       * @param a An argument to the curried function.
871       * @param b An argument to the curried function.
872       * @param c An argument to the curried function.
873       * @param d An argument to the curried function.
874       * @param e An argument to the curried function.
875       * @return A curried form of the given function.
876       */
877      public static <A, B, C, D, E, F$, G, H, I> F<F$, F<G, F<H, I>>> curry(final F8<A, B, C, D, E, F$, G, H, I> f,
878                                                                            final A a, final B b, final C c, final D d,
879                                                                            final E e) {
880        return curry(f).f(a).f(b).f(c).f(d).f(e);
881      }
882    
883      /**
884       * Curry a function of arity-8.
885       *
886       * @param f  The function to curry.
887       * @param a  An argument to the curried function.
888       * @param b  An argument to the curried function.
889       * @param c  An argument to the curried function.
890       * @param d  An argument to the curried function.
891       * @param e  An argument to the curried function.
892       * @param f$ An argument to the curried function.
893       * @return A curried form of the given function.
894       */
895      public static <A, B, C, D, E, F$, G, H, I> F<G, F<H, I>> curry(final F8<A, B, C, D, E, F$, G, H, I> f, final A a,
896                                                                     final B b, final C c, final D d, final E e,
897                                                                     final F$ f$) {
898        return curry(f).f(a).f(b).f(c).f(d).f(e).f(f$);
899      }
900    
901      /**
902       * Curry a function of arity-7.
903       *
904       * @param f  The function to curry.
905       * @param a  An argument to the curried function.
906       * @param b  An argument to the curried function.
907       * @param c  An argument to the curried function.
908       * @param d  An argument to the curried function.
909       * @param e  An argument to the curried function.
910       * @param f$ An argument to the curried function.
911       * @param g  An argument to the curried function.
912       * @return A curried form of the given function.
913       */
914      public static <A, B, C, D, E, F$, G, H, I> F<H, I> curry(final F8<A, B, C, D, E, F$, G, H, I> f, final A a, final B b,
915                                                               final C c, final D d, final E e, final F$ f$, final G g) {
916        return curry(f).f(a).f(b).f(c).f(d).f(e).f(f$).f(g);
917      }
918    
919      /**
920       * Uncurry a function of arity-8.
921       *
922       * @return An uncurried function.
923       */
924      public static <A, B, C, D, E, F$, G, H, I> F<F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>>, F8<A, B, C, D, E, F$, G, H, I>> uncurryF8() {
925        return new F<F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>>, F8<A, B, C, D, E, F$, G, H, I>>() {
926          public F8<A, B, C, D, E, F$, G, H, I> f(final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>> f) {
927            return uncurryF8(f);
928          }
929        };
930      }
931    
932      /**
933       * Uncurry a function of arity-8.
934       *
935       * @param f The function to uncurry.
936       * @return An uncurried function.
937       */
938      public static <A, B, C, D, E, F$, G, H, I> F8<A, B, C, D, E, F$, G, H, I> uncurryF8(
939          final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>> f) {
940        return new F8<A, B, C, D, E, F$, G, H, I>() {
941          public I f(final A a, final B b, final C c, final D d, final E e, final F$ f$, final G g, final H h) {
942            return f.f(a).f(b).f(c).f(d).f(e).f(f$).f(g).f(h);
943          }
944        };
945      }
946    
947      /**
948       * Binds the function in the second argument to the function in the first argument.
949       *
950       * @param ma A function whose argument type is the same as the argument type of the return value.
951       * @param f  A function whose argument type is the same as the return type of <em>ma</em>,
952       *           and yields the return value.
953       * @return A function that chains the given functions together such that the result of applying
954       *         <em>ma</em> to the argument is given to <i>f</i>, yielding a function
955       *         that is applied to the argument again.
956       */
957      public static <A, B, C> F<C, B> bind(final F<C, A> ma, final F<A, F<C, B>> f) {
958        return new F<C, B>() {
959          public B f(final C m) {
960            return f.f(ma.f(m)).f(m);
961          }
962        };
963      }
964    
965      /**
966       * Performs function application within a higher-order function (applicative functor pattern).
967       *
968       * @param cab The higher-order function to apply a function to.
969       * @param ca  A function to apply within a higher-order function.
970       * @return A new function after applying the given higher-order function to the given function.
971       */
972      public static <A, B, C> F<C, B> apply(final F<C, F<A, B>> cab, final F<C, A> ca) {
973        return bind(cab, new F<F<A, B>, F<C, B>>() {
974          public F<C, B> f(final F<A, B> f) {
975            return compose(new F<A, B>() {
976              public B f(final A a) {
977                return f.f(a);
978              }
979            }, ca);
980          }
981        });
982      }
983    
984      /**
985       * Binds the given function <em>f</em> to the values of the given functions, with a final join.
986       *
987       * @param ca A function to bind <em>f</em> function to.
988       * @param cb A function to bind <em>f</em> function to.
989       * @param f  The bound function to be composed with <em>ca</em> and then applied with <em>cb</em>
990       * @return A new function after performing the composition, then application.
991       */
992      public static <A, B, C, D> F<D, C> bind(final F<D, A> ca, final F<D, B> cb, final F<A, F<B, C>> f) {
993        return apply(compose(f, ca), cb);
994      }
995    
996      /**
997       * Applies a given function over the arguments of another function of arity-2.
998       *
999       * @param a The function whose arguments to apply another function over.
1000       * @param f The function to apply over the arguments of another function.
1001       * @return A function whose arguments are fed through function f, before being passed to function a.
1002       */
1003      public static <A, B, C> F<B, F<B, C>> on(final F<A, F<A, C>> a, final F<B, A> f) {
1004        return compose(compose(Function.<B, A, C>andThen().f(f), a), f);
1005      }
1006    
1007      /**
1008       * Promotes a function of arity-2 to a higher-order function.
1009       *
1010       * @param f The function to promote.
1011       * @return A function of arity-2 promoted to compose with two functions.
1012       */
1013      public static <A, B, C, D> F<F<D, A>, F<F<D, B>, F<D, C>>> lift(final F<A, F<B, C>> f) {
1014        return curry(new F2<F<D, A>, F<D, B>, F<D, C>>() {
1015          public F<D, C> f(final F<D, A> ca, final F<D, B> cb) {
1016            return bind(ca, cb, f);
1017          }
1018        });
1019      }
1020    
1021      /**
1022       * Joins two arguments of a function of arity-2 into one argument, yielding a function of arity-1.
1023       *
1024       * @param f A function whose arguments to join.
1025       * @return A function of arity-1 whose argument is substituted for both parameters of <em>f</em>.
1026       */
1027      public static <A, B> F<B, A> join(final F<B, F<B, A>> f) {
1028        return bind(f, Function.<F<B, A>>identity());
1029      }
1030    
1031    
1032      /**
1033       * Partial application of the second argument to the supplied function to get a function of type
1034       * <tt>A -> C</tt>. Same as <tt>flip(f).f(b)</tt>.
1035       *
1036       * @param f The function to partially apply.
1037       * @param b The value to apply to the function.
1038       * @return A new function based on <tt>f</tt> with its second argument applied.
1039       */
1040      public static <A, B, C> F<A, C> partialApply2(final F<A, F<B, C>> f, final B b) {
1041        return new F<A, C>() {
1042          public C f(final A a) {
1043            return uncurryF2(f).f(a, b);
1044          }
1045        };
1046      }
1047    
1048      /**
1049       * Partial application of the third argument to the supplied function to get a function of type
1050       * <tt>A -> B -> D</tt>.
1051       *
1052       * @param f The function to partially apply.
1053       * @param c The value to apply to the function.
1054       * @return A new function based on <tt>f</tt> with its third argument applied.
1055       */
1056      public static <A, B, C, D> F<A, F<B, D>> partialApply3(final F<A, F<B, F<C, D>>> f, final C c) {
1057        return new F<A, F<B, D>>() {
1058          public F<B, D> f(final A a) {
1059            return new F<B, D>() {
1060              public D f(final B b) {
1061                return uncurryF3(f).f(a, b, c);
1062              }
1063            };
1064          }
1065        };
1066      }
1067    
1068      /**
1069       * Partial application of the fourth argument to the supplied function to get a function of type
1070       * <tt>A -> B -> C -> E</tt>.
1071       *
1072       * @param f The function to partially apply.
1073       * @param d The value to apply to the function.
1074       * @return A new function based on <tt>f</tt> with its fourth argument applied.
1075       */
1076      public static <A, B, C, D, E> F<A, F<B, F<C, E>>> partialApply4(final F<A, F<B, F<C, F<D, E>>>> f, final D d) {
1077        return new F<A, F<B, F<C, E>>>() {
1078          public F<B, F<C, E>> f(final A a) {
1079            return new F<B, F<C, E>>() {
1080              public F<C, E> f(final B b) {
1081                return new F<C, E>() {
1082                  public E f(final C c) {
1083                    return uncurryF4(f).f(a, b, c, d);
1084                  }
1085                };
1086              }
1087            };
1088          }
1089        };
1090      }
1091    
1092      /**
1093       * Partial application of the fifth argument to the supplied function to get a function of type
1094       * <tt>A -> B -> C -> D -> F$</tt>.
1095       *
1096       * @param f The function to partially apply.
1097       * @param e The value to apply to the function.
1098       * @return A new function based on <tt>f</tt> with its fifth argument applied.
1099       */
1100      public static <A, B, C, D, E, F$> F<A, F<B, F<C, F<D, F$>>>> partialApply5(final F<A, F<B, F<C, F<D, F<E, F$>>>>> f,
1101                                                                                 final E e) {
1102        return new F<A, F<B, F<C, F<D, F$>>>>() {
1103          public F<B, F<C, F<D, F$>>> f(final A a) {
1104            return new F<B, F<C, F<D, F$>>>() {
1105              public F<C, F<D, F$>> f(final B b) {
1106                return new F<C, F<D, F$>>() {
1107                  public F<D, F$> f(final C c) {
1108                    return new F<D, F$>() {
1109                      public F$ f(final D d) {
1110                        return uncurryF5(f).f(a, b, c, d, e);
1111                      }
1112                    };
1113                  }
1114                };
1115              }
1116            };
1117          }
1118        };
1119      }
1120    
1121      /**
1122       * Partial application of the sixth argument to the supplied function to get a function of type
1123       * <tt>A -> B -> C -> D -> E -> G</tt>.
1124       *
1125       * @param f  The function to partially apply.
1126       * @param f$ The value to apply to the function.
1127       * @return A new function based on <tt>f</tt> with its sixth argument applied.
1128       */
1129      public static <A, B, C, D, E, F$, G> F<A, F<B, F<C, F<D, F<E, G>>>>> partialApply6(
1130          final F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>> f, final F$ f$) {
1131        return new F<A, F<B, F<C, F<D, F<E, G>>>>>() {
1132          public F<B, F<C, F<D, F<E, G>>>> f(final A a) {
1133            return new F<B, F<C, F<D, F<E, G>>>>() {
1134              public F<C, F<D, F<E, G>>> f(final B b) {
1135                return new F<C, F<D, F<E, G>>>() {
1136                  public F<D, F<E, G>> f(final C c) {
1137                    return new F<D, F<E, G>>() {
1138                      public F<E, G> f(final D d) {
1139                        return new F<E, G>() {
1140                          public G f(final E e) {
1141                            return uncurryF6(f).f(a, b, c, d, e, f$);
1142                          }
1143                        };
1144                      }
1145                    };
1146                  }
1147                };
1148              }
1149            };
1150          }
1151        };
1152      }
1153    
1154      /**
1155       * Partial application of the seventh argument to the supplied function to get a function of type
1156       * <tt>A -> B -> C -> D -> E -> F$ -> H</tt>.
1157       *
1158       * @param f The function to partially apply.
1159       * @param g The value to apply to the function.
1160       * @return A new function based on <tt>f</tt> with its seventh argument applied.
1161       */
1162      public static <A, B, C, D, E, F$, G, H> F<A, F<B, F<C, F<D, F<E, F<F$, H>>>>>> partialApply7(
1163          final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>> f, final G g) {
1164        return new F<A, F<B, F<C, F<D, F<E, F<F$, H>>>>>>() {
1165          public F<B, F<C, F<D, F<E, F<F$, H>>>>> f(final A a) {
1166            return new F<B, F<C, F<D, F<E, F<F$, H>>>>>() {
1167              public F<C, F<D, F<E, F<F$, H>>>> f(final B b) {
1168                return new F<C, F<D, F<E, F<F$, H>>>>() {
1169                  public F<D, F<E, F<F$, H>>> f(final C c) {
1170                    return new F<D, F<E, F<F$, H>>>() {
1171                      public F<E, F<F$, H>> f(final D d) {
1172                        return new F<E, F<F$, H>>() {
1173                          public F<F$, H> f(final E e) {
1174                            return new F<F$, H>() {
1175                              public H f(final F$ f$) {
1176                                return uncurryF7(f).f(a, b, c, d, e, f$, g);
1177                              }
1178                            };
1179                          }
1180                        };
1181                      }
1182                    };
1183                  }
1184                };
1185              }
1186            };
1187          }
1188        };
1189      }
1190    
1191      /**
1192       * Partial application of the eigth argument to the supplied function to get a function of type
1193       * <tt>A -> B -> C -> D -> E -> F$ -> G -> I</tt>.
1194       *
1195       * @param f The function to partially apply.
1196       * @param h The value to apply to the function.
1197       * @return A new function based on <tt>f</tt> with its eigth argument applied.
1198       */
1199      public static <A, B, C, D, E, F$, G, H, I> F<A, F<B, F<C, F<D, F<E, F<F$, F<G, I>>>>>>> partialApply8(
1200          final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>> f, final H h) {
1201        return new F<A, F<B, F<C, F<D, F<E, F<F$, F<G, I>>>>>>>() {
1202          public F<B, F<C, F<D, F<E, F<F$, F<G, I>>>>>> f(final A a) {
1203            return new F<B, F<C, F<D, F<E, F<F$, F<G, I>>>>>>() {
1204              public F<C, F<D, F<E, F<F$, F<G, I>>>>> f(final B b) {
1205                return new F<C, F<D, F<E, F<F$, F<G, I>>>>>() {
1206                  public F<D, F<E, F<F$, F<G, I>>>> f(final C c) {
1207                    return new F<D, F<E, F<F$, F<G, I>>>>() {
1208                      public F<E, F<F$, F<G, I>>> f(final D d) {
1209                        return new F<E, F<F$, F<G, I>>>() {
1210                          public F<F$, F<G, I>> f(final E e) {
1211                            return new F<F$, F<G, I>>() {
1212                              public F<G, I> f(final F$ f$) {
1213                                return new F<G, I>() {
1214                                  public I f(final G g) {
1215                                    return uncurryF8(f).f(a, b, c, d, e, f$, g, h);
1216                                  }
1217                                };
1218                              }
1219                            };
1220                          }
1221                        };
1222                      }
1223                    };
1224                  }
1225                };
1226              }
1227            };
1228          }
1229        };
1230      }
1231    }