Y combinator in small steps
The Y combinator is an interesting construct, allowing recursion without referring the function being recursed. In other words, call a function recursively, without naming it. We will go through one approach of deriving it.
This approach mostly follows WhyOfY by Richard P Gabriel 1. We will derive it in JavaScript, in steps. Each step is complete. Click on the ‘Edit in JSFiddle’ to explore the steps.
Premise & setup
Lets pick a simple example, so we can concentrate on exploring
recursion. Given a number, n
, return the sum of numbers from 1
to
n
. To start with, below is a recursive solution for the
problem. Individual steps are hosted in JSFiddle, for you to play
around.
The process
We have to remove the reference to sum
, inside the function, which
fortunately leads to the Y combinator. One approach to calling a
function, without using its name, is to pass the function as
parameter.
We have just moved the function name (reference) from inside the function, to the function call. As a next step, we could pass the function as a curried param.
This helps later, in abstracting the passing of function as parameter, out of the logic for the problem.
The double call inside the inner function, is quite irrelevant to the
problem of calculating sum. The logic of sum
shouldn’t know that
h(h)
gives the next function call. The recursive function should
just receive a function, to continue the recursion with. We could
abstract that in another function. Ex:
Why not pass h(h)
as parameter? Why do we have to wrap it in a
function?
Here is the complete version.
In the current version, the function dealing with the sum logic,
doesn’t have any dependency on context, or specific knowledge about
how to get the next function. Lets name it as sum
(for the time
being). Ex.
This is just so we can see the real changes in code. Here is the
recursion with sum
.
To evaluate the recursion, we had to call s4
with itself, ex
s4(s4)
. To not use a name, we would have to abstract it in a
function. We can define a function which s4
as parameter, and call
it with itself as parameter.
Expanding the definition of s4
gives.
We are almost done. Now, we just need to pass the actual function (ex
sum
in our case) as a parameter. Here is the Y
combinator.
Or in its inlined form:
Explorations
If you would like to think more about this, here are a few thoughts to explore.
-
We have only explored function with single argument. How could we make this work with multiple arguments.
-
Could we come up with a combinator, which doesn’t take curried version of sum. Ex a combinator which takes
sum
defined asfunction sum(f, n) { return n + f(n-1); }
as argument.
PS: ActiveSphere is hiring. If we can interest you, please visit our careers page.
1: A somewhat similar approach is followed by James Coglan’s blog post. And watch an interesting talk on it, by Jim Weirich.