v_//Z@g_=Z@g~g~v (* golfed *)
Z[g_][v_] = g[Z[g],v] (* ungolfed *)
Try it online!
This definition of the Z combinator uses the Wolfram Language's pattern-matching to make sure that any expression of the form Z[g]
remains unevaluated as long as the second argument is missing; only the two-argument form Z[g][v]
matches the above pattern and is replaced by g[Z[g],v]
, which in turn contains the single-argument form Z[g]
that remains unevaluated until later. This distinction between an inert single-argument form Z[g]
and an automatically-substituted two-argument form Z[g][v]
allows for a controlled recursion process that remains tied to the application of the second argument.
examples
factorial
fac[r_, n_] = If[n==0, 1, n*r[n-1]];
Table[Z[fac][i], {i, 0, 10}]
(* {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800} *)
Same with an anonymous function:
Table[Z[If[#2==0, 1, #2*#1[#2-1]]&][i], {i, 0, 10}]
(* {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800} *)
Same but using Mathematica's built-in self-reference operator #0
: we don't actually need a combinator to define recursive anonymous functions,
Table[If[#1==0, 1, #1*#0[#1-1]]&[i], {i, 0, 10}]
(* {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800} *)
Fibonacci sequence
fib[r_, n_] = If[n<=1, n, r[n-2]+r[n-1]];
Table[Z[fib][i], {i, 0, 10}]
(* {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55} *)
(define Y(lambda(f)(f(Y f))))
?) \$\endgroup\$