数日前、「C# での匿名再帰」についてこのサイトにアクセスしました。この記事の主旨は、次のコードは C# では機能しないということです。
Func<int, int> fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;
次に、カリー化とY コンビネーターを使用して C# の「匿名再帰」に戻る方法について詳しく説明します。これは非常に興味深いですが、私の日常のコーディングには少し複雑です。この時点で少なくとも...
私は自分の目で見るのが好きなので、Mono CSharp REPLを開いてその行に入りました。エラーなし。ということで、入りfib(8);
ました。驚いたことに、うまくいきました!REPL は21
!で応答しました。
これは REPL の魔法かもしれないと思ったので、「vi」を起動し、次のプログラムを入力してコンパイルしました。
using System;
public class Program
{
public static void Main(string[] args)
{
int x = int.Parse(args[0]);
Func<int, int> fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;
Console.WriteLine(fib(x));
}
}
それも完璧に構築され、実行されました!
Mac で Mono 2.10 を実行しています。現在、Windows マシンにアクセスできないため、Windows 上の .NET でこれをテストすることはできません。
これは .NET でも修正されていますか、それとも Mono のサイレント機能ですか? 記事は数年前のものです。
Mono のみの場合、次の就職の面接が待ちきれません。そこでは、.NET が機能しないという警告を提供する必要がある言語 (Mono C#) でフィビノッチ関数を作成するように求められます。まあ、実際、私は仕事が好きなので待つことができます。それにしても面白い…
アップデート:
fib
名前付きデリゲートとして使用しているため、Monoは実際には「匿名」再帰を行っていません。私の悪い。null
Mono C# コンパイラが代入前の値を想定するという事実は、fib
以下に示すバグです。私が「コンパイラ」と言ったのは、.NET C# コンパイラがコードをコンパイルしなくても、.NET CLR は結果のアセンブリを問題なく実行できるからです。
そこにあるすべてのナチスのインタビューについて:
Func<int, int> fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;
反復バージョンに置き換えることができます:
Func<int, int> fib = n =>
{
int old = 1;
int current = 1;
int next;
for (int i = 2; i < n; i++)
{
next = current + old;
old = current;
current = next;
}
return current;
};
C# のような言語では再帰バージョンが非効率的であるため、これを実行する必要がある場合があります。メモ化の使用を提案する人もいるかもしれませんが、これは反復的な方法よりもまだ遅いため、単に気まぐれである可能性があります。:-)
ただし、この時点で、これは他の何よりも関数型プログラミングの宣伝になります (再帰バージョンの方がはるかに優れているため)。元の質問とはまったく関係ありませんが、回答の一部は重要だと考えていました。