Named functions
The usual alternative is to use named functions and named recursion. Given an anonymous function, this can be done either by binding a name to the function, as in named function expressions in JavaScript, or by assigning the function to a variable and then calling the variable, as in function statements in JavaScript. Since languages that allow anonymous functions generally allow assigning these functions to variables (if not first-class functions), many languages do not provide a way to refer to the function itself, and explicitly reject anonymous recursion; examples include Go.[1]
For example, in JavaScript the factorial function can be defined via anonymous recursion as such:[2]
[1, 2, 3, 4, 5].map(function(n) {
return (!(n > 1)) ? 1 : arguments.callee(n-1) * n;
});
Rewritten to use a named function expression yields:
[1, 2, 3, 4, 5].map(function factorial(n) {
return (!(n > 1)) ? 1 : factorial(n-1) * n;
});
Passing functions as arguments
Even without mechanisms to refer to the current function or calling function, anonymous recursion is possible in a language that allows functions as arguments. This is done by adding another parameter to the basic recursive function and using this parameter as the function for the recursive call. This creates a higher-order function, and passing this higher function itself allows anonymous recursion within the actual recursive function. This can be done purely anonymously by applying a fixed-point combinator to this higher order function. This is mainly of academic interest, particularly to show that the lambda calculus has recursion, as the resulting expression is significantly more complicated than the original named recursive function. Conversely, the use of fixed-pointed combinators may be generically referred to as "anonymous recursion", as this is a notable use of them, though they have other applications.[3][4]
This is illustrated below using Python. First, a standard named recursion:
def fact(n):
if n == 0:
return 1
return n * fact(n - 1)
Using a higher-order function so the top-level function recurses anonymously on an argument, but still needing the standard recursive function as an argument:
def fact0(n0):
if n0 == 0:
return 1
return n0 * fact0(n0 - 1)
fact1 = lambda f, n1: 1 if n1 == 0 else n1 * f(n1 - 1)
fact = lambda n: fact1(fact0, n)
We can eliminate the standard recursive function by passing the function argument into the call:
fact1 = lambda f, n1: 1 if n1 == 0 else n1 * f(f, n1 - 1)
fact = lambda n: fact1(fact1, n)
The second line can be replaced by a generic higher-order function called a combinator:
F = lambda f: (lambda x: f(f, x))
fact1 = lambda f, n1: 1 if n1 == 0 else n1 * f(f, n1 - 1)
fact = F(fact1)
Written anonymously:[5]
(lambda f: (lambda x: f(f, x))) \
(lambda g, n1: 1 if n1 == 0 else n1 * g(g, n1 - 1))
In the lambda calculus, which only uses functions of a single variable, this can be done via the Y combinator. First make the higher-order function of two variables be a function of a single variable, which directly returns a function, by currying:
fact1 = lambda f: (lambda n1: 1 if n1 == 0 else n1 * f(f)(n1 - 1))
fact = fact1(fact1)
There are two "applying a higher order function to itself" operations here: f(f)
in the first line and fact1(fact1)
in the second. Factoring out the second double application into a combinator yields:
C = lambda x: x(x)
fact1 = lambda f: (lambda n1: 1 if n1 == 0 else n1 * f(f)(n1 - 1))
fact = C(fact1)
Factoring out the other double application yields:
C = lambda x: x(x)
D = lambda f: (lambda x: f(lambda v: x(x)(v)))
fact1 = lambda g: (lambda n1: 1 if n1 == 0 else n1 * g(n1 - 1))
fact = C(D(fact1))
Combining the two combinators into one yields the Y combinator:
C = lambda x: x(x)
D = lambda f: (lambda x: f(lambda v: x(x)(v)))
Y = lambda y: C(D(y))
fact1 = lambda g: (lambda n1: 1 if n1 == 0 else n1 * g(n1 - 1))
fact = Y(fact1)
Expanding out the Y combinator yields:
Y = lambda f: (lambda x: f(lambda v: x(x)(v))) \
(lambda x: f(lambda v: x(x)(v)))
fact1 = lambda g: (lambda n1: 1 if n1 == 0 else n1 * g(n1 - 1))
fact = Y(fact1)
Combining these yields a recursive definition of the factorial in lambda calculus (anonymous functions of a single variable):[6]
(lambda f: (lambda x: f(lambda v: x(x)(v)))
(lambda x: f(lambda v: x(x)(v)))) \
(lambda g: (lambda n1: 1 if n1 == 0 else n1 * g(n1 - 1)))