Анонимная рекурсия в C # имеет потрясающую дискуссию на эту тему.
Рекурсия прекрасна, и лямбды
конечная абстракция. Но как можно
они будут использоваться вместе? Лямбды
анонимные функции и рекурсия
требует имен ...
Так как это снова появилось, вот пример использования Y-комбинатора:
// 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;
}
Вот его использование для вызова анонимной, рекурсивной функции ...
Func<int,int> exp = Y<int,int>( e => x => ( x <=1 ) ? 1 : x * e( x - 1 ) );
Console.WriteLine( exp(5) );
Вы заметите, что если вы не используете Y-комбинатор и не настроите рекурсию только с делегатом, вы не получите правильную рекурсию. Например ...
// This is BAD. Do not do this!
Func<int,int> badRec = null;
badRec = x => ( x <= 1 ) ? 1 : x * badRec( x - 1 );
Но все отлично работает ...
Console.WriteLine( badRec(5) );
// Output
// 120
Но попробуйте это ...
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
Что?!?
Видите ли, после строки badRec = x => x + 1;
делегат, который у вас действительно есть, это ...
badRecCopy = x => ( x <= 1 ) ? 1 : x * ( (x+1)-1 );
Итак, badRec увеличивает значение на 1, которое мы ожидаем (4+1=5)
, но badRecCopy теперь фактически возвращает квадрат значения (5*( (5+1)-1 )
, которого мы почти наверняка не ожидали.
Если вы используете Y-комбинатор, он будет работать как положено ...
Func<int,int> goodRec = Y<int,int>( exp => x => ( x <=1 ) ? 1 : x * exp( x - 1 ) );
Func<int,int> goodRecCopy = goodRec;
И вы получаете то, что ожидаете.
goodRec = x => x + 1;
Console.WriteLine( goodRec(4) );
Console.WriteLine( goodRecCopy(5) );
// Output
// 5
// 120
Вы можете узнать больше о Y-комбинаторе (PDF Link).