Работает ли «Анонимная рекурсия» в .NET? Это работает в Mono

Я зашел на этот сайт несколько дней назад по теме «Анонимная рекурсия в C #». Суть статьи заключается в том, что следующий код не будет работать на C #:

Func 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 fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;
        Console.WriteLine(fib(x));
    }
}

Он тоже построен и отлично работает!

Я запускаю Mono 2.10 на Mac. У меня сейчас нет доступа к машине с Windows, поэтому я не могу протестировать это на .NET в Windows.

Было ли это исправлено и на .NET, или это скрытая функция Mono? Этой статье уже несколько лет.

Если это только Mono, я не могу дождаться следующего собеседования, на котором меня попросят написать функцию Фибинокчи на языке по моему выбору (Mono C #), где я должен предоставить предостережение, что .NET работать не будет. Что ж, на самом деле я могу подождать, так как я люблю свою работу. Тем не менее, интересно ...

Обновление:

Mono на самом деле не выполняет «анонимную» рекурсию, поскольку использует fib в качестве именованного делегата. Виноват. Тот факт, что компилятор Mono C # принимает значение null для fib перед назначением, является ошибкой, как указано ниже. Я говорю «компилятор», потому что .NET CLR будет нормально запускать полученную сборку, даже если компилятор .NET C # не скомпилирует код.

Для всех интервью, нацистов:

Func fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;

можно заменить итеративным версия:

Func 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 #. Некоторые могут предложить использовать мемоизацию , но, поскольку это все еще медленнее, чем итерационный метод, они могут просто дрочить. : -)

На данный момент, однако, это становится больше рекламой функционального программирования, чем чем-либо еще (поскольку рекурсивная версия намного лучше). Это действительно не имеет ничего общего с моим первоначальным вопросом, но некоторые из ответов сочли это важным.

5
задан Justin 30 March 2011 в 17:18
поделиться