How to write a recursive lambda

Easy, isn’t it?

At first glance, this problem looks quite easy, isn’t it? Let’s try:

Func<int, int> factorial = x => x == 0 ? 1 : x * factorial(x - 1);

Unfortunately, the above code will fail to compile, because factorial is used when unassigned.

So, how about we assign it before doing this:

Func<int, int> factorial = null;
factorial = x => x == 0 ? 1 : x * factorial(x - 1);

Yay! This time the code compiles! Problem solved, isn’t it?

Well, sort of, unless we continue to write:

var f2 = factorial;
factorial = i => i;

Console.WriteLine(f2(5));

This will output 20 instead of 120, because f2 becomes the following when factorial = i => i

x => x == 0 ? 1 : x * (i => i)(x - 1)

So, what now?

Map from a function to another function

Consider the following map function:

Func<Func<int, int>, Func<int, int>> map = f => x => x == 0 ? 1 : x * f(x - 1);

It takes a function f, and returns a function that uses f as if it’s a factorial function.

If f is indeed a factorial function, then the resulting function will be a factorial function.

Fixed-points of a function

Generally, if x = g(x), then x is a fixed-point of g. Let’s say x = Fix(g).

In our case, because applying a factorial function f to map gives us a factorial function, a factorial function is actually a fixed-point of map, which is Fix(map). So f = Fix(map).

Now let’s find Fix(g):

static Func<T, T> Fix<T>(Func<Func<T, T>, Func<T, T>> g)
{
    // ...
}

By definition, we have x = g(x), because x = Fix(g), we have Fix(g) = g(Fix(g)). So we have:

static Func<T, T> Fix<T>(Func<Func<T, T>, Func<T, T>> g)
{
    return g(Fix(g));
}

Not quite yet, because we are here to work out a fixed-point definition of g, not executing it, we need one more step:

static Func<T, T> Fix<T>(Func<Func<T, T>, Func<T, T>> g)
{
    return x => g(Fix(g))(x);
}

Essentially this function is creating a function that gets the fixed-point function of g and then calls g.

Result

Now if we apply Fix(map) to map, which is map(Fix(map)), it will return our factorial function. But Fix(map) itself is aleady a factorial function!

Full source:

class Program
{
    static void Main( string[] args )
    {
        Func<Func<int, int>, Func<int, int>> map
            = fac => x => x == 0 ? 1 : x * fac(x - 1);

        var factorial = Fix(map);

        Console.WriteLine(factorial(5));
    }

    static Func<T, T> Fix<T>(Func<Func<T, T>, Func<T, T>> g)
    {
        return x => map(Fix(g))(x);
    }
}

How to write a recursive lambda
https://blog.bigpower.dev/How-to-write-a-recursive-lambda/
Author
Paul Chen
Posted on
August 15, 2009
Licensed under