He navegado en el sitio this hace unos días en "Recursividad anónima en C#". La idea central del artículo es que el siguiente código no funcionará en C#:¿Funciona la "Recursividad anónima" en .NET? Lo hace en Mono
Func<int, int> fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;
El artículo entonces entra en algunos detalles acerca de cómo usar currying y la Y-combinator para volver a "Anónimo recursividad" en C#. Esto es bastante interesante, pero un poco complejo para mi codificación diaria, me temo. En este punto al menos ...
Me gusta ver cosas para mí, así que abrí el Mono CSharp REPL y entré en esa línea. Sin errores. Entonces, ingresé fib(8);
. ¡Para mi gran sorpresa, funcionó! ¡El REPL respondió de nuevo con 21
!
Pensé que tal vez esto era algo mágico con el REPL, así que encendí 'vi', escribí el siguiente programa y lo compilé.
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));
}
}
¡Construyó y funcionó perfectamente también!
Estoy ejecutando Mono 2.10 en una Mac. No tengo acceso a una máquina con Windows ahora mismo, así que no puedo probar esto en .NET en Windows.
¿Se ha corregido esto también en .NET o esta es una función silenciosa de Mono? El artículo tiene un par de años.
Si solo es Mono, no puedo esperar para la próxima entrevista de trabajo en la que me piden que escriba una función de Fibinocci en el idioma de mi elección (Mono C#) donde tengo que advertir que .NET no funcionará . Bueno, en realidad puedo esperar ya que amo mi trabajo. Aún así, interesante ...
Actualización:
Mono no está haciendo realmente recursividad "anónimo", como se usa fib
como delegado nombrado. Mi error. El hecho de que el compilador Mono C# asuma un valor null
para fib
antes de la asignación es un error como se indica a continuación. Digo "compilador" porque .NET CLR ejecutará el ensamblaje resultante muy bien, aunque el compilador .NET C# no compile el código.
Para todos los nazis de la entrevista por ahí:
Func<int, int> fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;
se pueden sustituir por una versión iterativa:
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;
};
Es posible que desee hacer esto debido a que la versión recursiva es ineficiente en un lenguaje como DO#. Algunos pueden sugerir el uso de memoization, pero, dado que esto es aún más lento que el método iterativo, pueden estar siendo más tontos. :-)
En este punto, sin embargo, esto se convierte más en un anuncio para programación funcional que en cualquier otra cosa (ya que la versión recursiva es mucho más agradable). Realmente no tiene nada que ver con mi pregunta original, pero algunas de las respuestas pensaron que era importante.
Si algún entrevistador de trabajo me preguntara si me iría. – JonH
¡La última vez que revisé usted todavía tiene que declarar el 'Func' en una línea separada, estaría feliz de ser incorrecto! – BrokenGlass
Lo intenté y C# 3.5 falla. –