Несколько дней назад я зашел на этот сайт на тему "Анонимная рекурсия в C #". Суть статьи в том, что следующий код не будет работать в C #:
Func<int, int> fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;
Далее в статье подробно рассказывается, как использовать curry и Y-комбинатор , чтобы вернуться к "Anonymous Recursion" в C #. Боюсь, это довольно интересно, но немного сложнее для моего повседневного программирования. На данный момент, по крайней мере ...
Мне нравится видеть вещи для себя, поэтому я открыл Mono CSharp REPL и вошел в эту строку. Нет ошибок Итак, я ввел fib(8);
. К моему большому удивлению, это сработало! Ответ ответил с 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));
}
}
Он тоже построен и отлично работает!
Я использую Mono 2.10 на Mac. У меня сейчас нет доступа к машине с Windows, поэтому я не могу проверить это на .NET в Windows.
Это также было исправлено в .NET или это тихая функция Mono? Этой статье пару лет.
Если это только Mono, я не могу дождаться следующего собеседования, где меня попросят написать функцию Fibinocci на выбранном мной языке (Mono C #), где я должен предоставить предупреждение о том, что .NET не будет работать. Ну, на самом деле я могу подождать, так как я люблю свою работу. Все-таки интересно ...
Обновление:
Mono на самом деле не выполняет "анонимную" рекурсию, поскольку использует fib
в качестве именованного делегата. Виноват. Тот факт, что компилятор Mono C # принимает значение null
для fib
перед назначением, является ошибкой, как отмечено ниже. Я говорю «компилятор», потому что .NET CLR прекрасно запускает полученную сборку, даже если компилятор .NET C # не компилирует код.
За все интервью там нацистов:
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 #. Некоторые могут предложить использовать memoization , но, поскольку это все же медленнее, чем итеративный метод, они могут быть просто чудовищами. : -)
Однако в этот момент это становится скорее рекламой для функционального программирования, чем чем-либо еще (поскольку рекурсивная версия намного приятнее). Это на самом деле не имеет ничего общего с моим первоначальным вопросом, но некоторые из ответов считают, что это важно.