Anonymous Recursion in C# tiene una excelente discusión sobre este tema.
Recursión es hermosa y lambdas son la máxima abstracción. Pero, ¿cómo pueden usarse juntos? Lambdas son funciones anónimas y recursividad requiere nombres ...
Dado que este apareció de nuevo, aquí hay un ejemplo del uso de la Y-Combinator:
// This is the combinator
public static Func<A,R> Y<A,R>(Func<Func<A,R>, Func<A,R>> f)
{
Func<A,R> g = null;
g = f(a => g(a));
return g;
}
aquí hay un uso de él para llamar a una anónima, función recursiva ...
Func<int,int> exp = Y<int,int>(e => x => (x <=1) ? 1 : x * e(x - 1));
Console.WriteLine(exp(5));
se dará cuenta de que si no se utiliza la y-Combinator y configura la recursividad con sólo el delegado, usted no consigue corre ct recursión. Por ejemplo ...
// This is BAD. Do not do this!
Func<int,int> badRec = null;
badRec = x => (x <= 1) ? 1 : x * badRec(x - 1);
Pero todo funciona bien ...
Console.WriteLine(badRec(5));
// Output
// 120
Pero prueba este ...
Func<int,int> badRec = null;
badRec = x => (x <= 1) ? 1 : x * badRec(x - 1);
Func<int,int> badRecCopy = badRec;
badRec = x => x + 1;
Console.WriteLine(badRec(4));
Console.WriteLine(badRecCopy(5));
// Output
// 5
// 25
¿Qué?!?
Ves, después de la línea badRec = x => x + 1;
, el delegado que tiene actualmente es esto ...
badRecCopy = x => (x <= 1) ? 1 : x * ((x+1)-1);
Así, badRec está incrementando el valor en 1 que esperamos (4+1=5)
, pero badRecCopy está ahora en realidad la devolución de los cuadrado del valor (5*((5+1)-1)
que casi con seguridad no esperábamos.
Si utiliza la Y-Combinator, que funcionará como se espera ...
Func<int,int> goodRec = Y<int,int>(exp => x => (x <=1) ? 1 : x * exp(x - 1));
Func<int,int> goodRecCopy = goodRec;
y se obtiene lo que espera.
goodRec = x => x + 1;
Console.WriteLine(goodRec(4));
Console.WriteLine(goodRecCopy(5));
// Output
// 5
// 120
Puede leer más sobre el Y-combinator (PDF Link).
La queja exacta de VS2008 es: variable local 'construir' no puede ser inicializado antes accediendo – Matt