C# 中的匿名递归对此主题进行了精彩的讨论。
递归很漂亮,而 lambdas 是终极抽象。但是它们怎么能一起使用呢?Lambda 是匿名函数,递归需要名称...
由于这再次弹出,这里是使用 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 链接)。