package ch.claude_martin; import java.util.function.*; /** * My Y Combinator can handle any reference type (primitives will be auto-boxed, * that's why I can use long/Long here). However, since I'm using * {@link UnaryOperator}, the recursive function must return the same type as * it's (second) argument. Factorial is a good example of this. Instead of long, * it could take a {@link java.math.BigInteger} and also return one. * */ public class YComb { /** * This is the recursive type of the function that will apply itself to * itself. This is how the recursion work.s A function needs itself as the first * parameter, so it then can call itself recursively. *

See this partial application in the code below:
* b -> b.apply(b) */ interface Fn2Op extends Function, UnaryOperator> { } /** Prints the factorial of args[0].*/ public static void main(String args[]) { final UnaryOperator> factorial = f -> n -> (n == 0) ? 1L : n * f.apply(n - 1); System.out.println(apply(factorial, Long.parseLong(args[0]))); } /** * Takes any recursive function (which takes itself and an argument) and * argument and returns the result. The argument and the return value are of the * same type T. * * @param The type of arg and return value * @param fn The recursive function (in curried form) * @param arg The argument for the function * @return the result of applying arg to fn */ private static T apply(UnaryOperator> fn, T arg) { return ((Function>, UnaryOperator>) a -> ((Fn2Op) b -> b.apply(b)) .apply( c -> a.apply( x -> c.apply(c).apply(x) ) )).apply(fn).apply(arg); } }