public interface Fn<A, B> { B apply(A a); static <X> Fn<X, X> I() { return x -> x; } // Kxy = x static <X, Y> Fn<X, Fn<Y, X>> K() { return x -> y -> x; } // Sxyz = xz(yz) static <X, Y, Z> Fn<Fn<Z, Fn<Y, X>>, Fn<Fn<Z, Y>, Fn<Z, X>>> S() { return x -> y -> z -> x.apply(z).apply(y.apply(z)); } // Yf=f(Yf) interface Y<A> extends Fn<Y<A>, Fn<A, A>> { static <A> Y<A> Y() { return f -> f.apply(f); } } static <A> Fn<Fn<Fn<A, A>, Fn<A, A>>, Fn<A, A>> Y() { return g -> Y.<A>Y().apply(f -> g.apply(x -> f.apply(f).apply(x))); } }