Recursive Linq Functions

You might have tried writing a recursive Linq function and run into problems. For instance, the following doesn’t work because ‘factorial’ isn't defined when the right-hand side of the assignment is being evaluated:
 
//Error: Use of unassigned local variable 'factorial'
Func<int, int> factorial =
 n => n < 2 ? 1 : n * factorial(n - 1);
 
However, because you’re writing a lambda expression with Linq, you can use the Y combinator, a function that takes your code and returns a recursive version. It’s a bit odd, requiring no little attention to understand, but it works well. For instance, using the Y combinator, you can write the following code:
 
Func<int, int> factorial =
 Extensions.YCombinator<int, int>(
  fact =>
   n => n < 2 ? 1 : n * fact(n - 1));
 
And then you can call it as you expect, e.g., factorial(5) returns 120.
 
Intuitively, the Y combinator works by calling your function on itself. Its ideas are closely related to self-reproducing code. For details, I recommend either “The Why of Y” or “Fixed Point Combinator.” Though cool, the Y combinator isn’t a panacea for all recursion – as Arvind et al note: “While the existence of the Y combinator is mathematically fascinating, fixed points [like the Y combinator] do not provide a simple encapsulation of recursion. For example, we would like to be able to declare mutually recursive functions and data structures in such a way that their definitions are clear and readable; the need to re-shape such definitions as fixed points plays havoc with such an endeavor.
 
Here is an implementation of the Y combinator for Linq that Mads Torgersen and I wrote, for both delegates and expressions. (The expression implementation will be a lot simpler when Linq provides an invocation syntax for expressions.)
 

Posted Aug 18 2006, 09:57 PM by jeffrey-schlimmer

Comments

Alex James wrote re: Recursive Linq Functions
on 08-19-2006 11:42 AM
Nice thanks for the great info...
Henk de Koning wrote re: Recursive Linq Functions
on 09-11-2006 4:24 AM
Although I really liked your Y combinator, in the simple case of factorials and Fibonacci's, I think one might be better of with:

Func<int, int> fib = null;
fib = n => (n < 2) ? 1 : fib(n-1) + fib(n-2);

:-)

I guess the problem really applies to situations where you cannot separate declaration and definition ?
Michael wrote re: Recursive Linq Functions
on 01-11-2007 12:29 PM
Pretty cool! Some nitpicking though: It seems to me that this is not the Y combinator but rather Turing's fixedpoint combinator T = (?x. ?y. (y (x x y))) (?x. ?y. (y (x x y)))

Michal

Add a Comment

(required)  
(optional)
(required)  
Remember Me?