32

Is it possible to do recursion with an Func delegate? I have the following, which doesn't compile because the name of the Func isn't in scope...

Func<long, long, List<long>, IEnumerable<long>> GeneratePrimesRecursively = (number, upperBound, primeFactors) => 
{
    if (upperBound < number)
    {
        return primeFactors;
    }
    else
    {
        if (!primeFactors.Any(factor => number % factor == 0)) primeFactors.Add(number);
        return GeneratePrimesRecursively(++number, upperBound, primeFactors); // breaks here.
    }
};
t3rse
  • 10,024
  • 11
  • 57
  • 84
  • That works out-of-the-box on Mono http://www.ienablemuch.com/2010/11/simulate-nested-recursive-function-in-c_08.html – Michael Buen Jan 06 '11 at 04:10
  • This is a duplicate of http://stackoverflow.com/questions/1079164/c-recursive-functions-with-lambdas/1079609#1079609 – Eric Lippert Jan 06 '11 at 16:31

1 Answers1

58

Like this:

Func<...> method = null;
method = (...) => {
    return method();
};

Your code produces an error because you're trying to use the variable before you assign it.
Your lambda expression is compiled before the variable is set (the variable can only be set to a complete expression), so it cannot use the variable.
Setting the variable to null first avoids this issue, because it will already be set when the lambda expression is compiled.

As a more powerful approach, you can use a YCombinator.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • +1 For the work-about. I really wish C# was "smart" enough to work without this construct though. (On the other hand, some languages have different syntax for functions and recursive-function bindings.) –  Jan 06 '11 at 03:52
  • @pst: See my expanded explanation. – SLaks Jan 06 '11 at 03:53
  • @Slaks Yeah, yeah -- but this case *could* be part of the C# specification (to make the scope of lambdas include the declaration statement they are in, if any) -- in which case it'd be perfectly legal and accepted. It's just wishful thinking for now. –  Jan 06 '11 at 10:50
  • @pst: No, it couldn't. A lambda expression has nothing to do with a variable. – SLaks Jan 06 '11 at 13:24
  • 2
    @SLaks, @pst: pst has the right idea here but the details are not quite right. The reason this *could* be legal is because we could deduce *at compile time* that the variable "method" could not be read by the execution lambda body until after it was written. We could know this because static analysis could show that the initialization does not invoke the lambda. Essentially what we'd need to do is tell the compiler that the delegate constructor that takes the reference to the anonymous method does not invoke it. We could thereby suppress the definite assignment error. – Eric Lippert Jan 06 '11 at 16:35
  • Thanks, that helped a lot. – VSO Aug 23 '16 at 20:53