import java.math.BigInteger; import java.util.Arrays; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; interface Function { public static final List NIL = Collections.emptyList(); public OUTPUT call(List input); } class Functions { public static OUTPUT call( Function f) { return f.call(Function.NIL); } public static OUTPUT call( Function f, INPUT input) { return f.call(Collections.singletonList(input)); } public static OUTPUT call( Function f, INPUT... input) { return f.call(Arrays.asList(input)); } public static OUTPUT call( Function f, Class type, INPUT... input) { List i = Collections.checkedList(new ArrayList(), type); i.addAll(Arrays.asList(input)); return f.call(i); } public static T input( List input, int index) { return input.size() > index ? input.get(index) : null; } public static Function compose( final Function f , final Function g) { return new Function() { @Override public OUTPUT call(List input) { return f.call(Collections.singletonList(g.call(input))); } }; } public static Function y( final Function, Function> f) { return new Function() { @Override public OUTPUT call(List input) { return Functions.call(f, new Function() { @Override public OUTPUT call(List input) { return y(f).call(input); } }).call(input); } }; } } public class Y { public static BigInteger TWO = BigInteger.ONE.add(BigInteger.ONE); public static void main(String[] args) { Function fibonacci = Functions.y( new Function, Function>() { @Override public Function call(List> input) { final Function f = Functions.input(input, 0); return new Function() { @Override public Number call(List input) { BigInteger n = new BigInteger(Functions.input(input, 0).toString()); if (n.compareTo(TWO) <= 0) return 1; return new BigInteger(Functions.call(f, n.subtract(BigInteger.ONE)).toString()) .add(new BigInteger(Functions.call(f, n.subtract(TWO)).toString())); } }; } } ); Function factorial = Functions.y( new Function, Function>() { @Override public Function call(List> input) { final Function f = Functions.input(input, 0); return new Function() { @Override public Number call(List input) { BigInteger n = new BigInteger(Functions.input(input, 0).toString()); if (n.compareTo(BigInteger.ONE) <= 0) return 1; return n.multiply( new BigInteger(Functions.call(f, n.subtract(BigInteger.ONE)).toString()) ); } }; } } ); Function ackermann = Functions.y( new Function, Function>() { @Override public Function call(List> input) { final Function f = Functions.input(input, 0); return new Function() { @Override public Number call(List input) { BigInteger m = new BigInteger(Functions.input(input, 0) + ""); BigInteger n = new BigInteger(Functions.input(input, 1) + ""); return m.equals(BigInteger.ZERO) ? n.add(BigInteger.ONE) : Functions.call(f, m.subtract(BigInteger.ONE), n.equals(BigInteger.ZERO) ? BigInteger.ONE : Functions.call(f, m, n.subtract(BigInteger.ONE))); } }; } } ); System.out.println("fibonacci(10) = " + Functions.call(fibonacci, 10)); System.out.println("factorial(10) = " + Functions.call(factorial, 10)); System.out.println("ackermann(3, 7) = " + Functions.call(ackermann, 3, 7)); } }