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