C#中的匿名递归对这个主题进行了精彩的讨论。
递归很美妙,而lambda是最终的抽象。但它们如何结合使用?Lambda是匿名函数,递归需要名称...
既然这又出现了,这里有一个使用Y组合器的示例:
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) );
什么?!?
你看,经过这行代码 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) );
你可以阅读有关Y组合子的更多信息(PDF链接)。