【问题标题】:C# anonymous function recursionC#匿名函数递归
【发布时间】:2020-09-24 01:05:30
【问题描述】:

如果我错了,请纠正我,但我在网上找不到像这样直截了当的东西。 假设您有以下内容:

        static Func<int,int> GetInt(int n)
        {
            return (int y) =>
            {
                if (y < 2)
                    return (y);
                return 
                    GetInt(n - 1)(y) - GetInt(n - 2)(y);
            };
        }

尝试通过调用此匿名函数来获取结果会返回类似 System.Func`2[System.Int32,System.Int32] 的内容。 如何使用匿名函数实现递归。为了得到结果,我如何转换作为实际函数的返回值?

【问题讨论】:

  • ...但是为什么要使用匿名函数呢?给那只小狗起个名字,让它更容易理解?
  • 这个函数到底有什么意义?第一次调用将返回匿名函数,随后的调用将调用创建更多匿名函数。我不认为这个想法是为了使功能无效
  • @OptionalOption 这是编写适当的匿名递归函数的第一步......主要是教育练习,但有助于更深入地理解语言 - weblogs.asp.net/dixin/…,或搜索“C# y 组合器”(不要与同名网站混淆)。
  • 请注意,您期望此代码执行的操作非常令人困惑(正如@OptionalOption 指出的那样,帖子中显示的内容将堆栈溢出)...通常人们以 n 开头!或斐波那契数,当他们尝试递归时 - 问题中的样本在尝试计算的值方面非常混乱。
  • 变量n 甚至没有在这个函数中使用。它已经被淘汰了。

标签: c# linq recursion anonymous-function


【解决方案1】:

您似乎正在按如下方式调用该函数:

var result = GetInt(valueOfN);

请注意,上述GetInt 方法本身返回一个函数。因此,要获得内部函数返回的结果,您需要这样做:

var result = GetInt(valueOfN)(valueOfY);

【讨论】:

  • 这是保证堆栈溢出。
  • @OptionalOption 虽然情况可能如此。这与提出的问题完全不同。提出的问题是“如何调用内部函数”而不是“可能出现什么问题以及如何解决它们”。那是供OP调查和修复的。在发这篇文章时,我并没有过多关注代码的实际作用,否则我会注意到并提出一些建议,但正如所说的那样,这与问题完全无关,对我来说只是一个奖励。
  • 这不是递归调用自身的匿名函数。它是一个匿名函数,递归地创建其他匿名函数。
【解决方案2】:

看起来你已经修改了这个函数。

变量n 未被用于以任何方式创建Func&lt;int, int&gt;,变量y 未被修改。 Func&lt;int, int&gt; 因此只会导致堆栈溢出。

如果我假设 yn 是同一个变量,那么你的方法真的可以归结为:

static Func<int,int> GetInt()
{
    Func<int, int> f = y =>
    {
        if (y < 2)
            return y;
        return 
            f(y - 1) - f(y - 2);
    };
    return f;
}

但这给了我一个错误:

使用未赋值的局部变量'f'

这只是让我们回到你的问题:

如何使用匿名函数实现递归?

这很容易。只需先将null 分配给函数,然后就可以使用递归了。

这给了我:

static Func<int,int> GetInt()
{
    Func<int, int> f = null;
    f = y =>
    {
        if (y < 2)
            return y;
        return 
            f(y - 1) - f(y - 2);
    };
    return f;
}

这非常好用。

【讨论】:

    【解决方案3】:

    正如其他答案中提到的问题中的代码

    • 不调用结果函数,而是打印结果类型的ToString(),它确实是System.Func'2[System.Int32,System.Int32]answer by Ousmane D.
    • 代码是无限递归的,因为它从不检查 n 的值(answer by Optional Option

    您可能会追求的是Y-combinator (or fixed-point combinator),可以说将非递归函数转换为递归函数。这在许多文章和 SO 问题中都有涉及,例如 Do we need fixed point combinators in C#?Have I implemented Y-combinator using C# dynamic, and if I haven't, what is it?

    您可能可以从不太复杂的变体开始,该变体出现在提出 y-combinator 完整代码的中间步骤:

    • 递归函数可以表示为接受参数和函数递归调用的函数。请注意,GetInt 不会递归调用自身,它会递归调用“some”函数,因此这不是严格意义上的“安全”方法——完整实现请参见上面的链接。

      静态 int GetInt(Func f, int n) { 返回 n

    • 要调用该函数本身,我们需要将该函数(类型为Func&lt;Func&lt;int,int&gt;, int, int&gt;)转换为Func&lt;int, int&gt;,并将其作为第一个参数传递。所以我们可以创建帮助方法来完成它。在r 下面的方法中是“递归函数应该调用来进行递归的函数”。请注意,我们必须先初始化它,因为我们使用它的值来定义结果函数:

      Func<int, int> Rec(Func<Func<int, int>, int, int> f)
      {
          Func<int, int> r = null; 
          r = n => f(r, n);
      
          return r;
      }
      
    • 现在我们可以制作匿名递归函数了:

      Func<int,int> recursiveGetInt = Rec(GetInt);
      Console.WriteLine(recursiveGetInt (5));
      
      Func<int,int> anonymousFactorial = Rec((f, n)=> n == 1 ? 1 : n * f(n-1));
      Console.WriteLine(anonymousFactorial (5));
      
      Console.WriteLine("Anonymous Fibonacci of 5: {0}",
           ((f, n)=> n == 1 ? 1 : f(n-1) + f(n-2)) (5));
      

    【讨论】:

      猜你喜欢
      • 2022-06-20
      • 2015-11-21
      • 2011-01-29
      • 2011-04-22
      • 1970-01-01
      • 2011-07-17
      • 2011-10-24
      • 2013-07-11
      • 1970-01-01
      相关资源
      最近更新 更多