¿Qué hay en la programación funcional que hace la diferencia?
La programación funcional es por principio declarativa . Dices cuál es tu resultado en lugar de cómo calcularlo.
Echemos un vistazo a la implementación realmente funcional de su fragmento. En Haskell sería:
predsum pred numbers = sum (filter pred numbers)
¿Está claro cuál es el resultado? Entonces, es la suma de los números que se encuentran con el predicado. ¿Cómo se calcula? No me importa, pregunta al compilador.
Posiblemente podría decir que usar sum
y filter
es un truco y no cuenta. Deje que se implemente sin estos ayudantes (aunque la mejor forma sería implementarlos primero)
La solución "Functional Programming 101" que no utiliza sum
es con recursividad:
sum pred list =
case list of
[] -> 0
h:t -> if pred h then h + sum pred t
else sum pred t
Todavía está bastante claro cuál es el resultado en términos de llamada de función única. Es 0
, o recursive call + h or 0
, dependiendo de pred h
. Sigue siendo bastante sencillo, incluso si el resultado final no es inmediatamente obvio (aunque con un poco de práctica, esto realmente se lee como un for
bucle).
Compare eso con su versión:
public int Sum(Func<int,bool> predicate, IEnumerable<int> numbers){
int result = 0;
foreach(var item in numbers)
if (predicate(item)) result += item;
return result;
}
Cual es el resultado? Oh, ya veo: una sola return
declaración, sin sorpresas aquí: return result
.
Pero que es result
? int result = 0
? No parece correcto Haces algo más tarde con eso 0
. Ok, le agregas item
s. Y así.
Por supuesto, para la mayoría de los programadores, es bastante obvio lo que sucede en una función simple como esta, pero agregue una return
declaración adicional o algo así y de repente se vuelve más difícil de rastrear. Todo el código trata sobre cómo y qué queda para que el lector descubra: este es claramente un estilo muy imperativo .
Entonces, ¿las variables y los bucles están mal?
No.
Hay muchas cosas que son mucho más fáciles de explicar por ellos, y muchos algoritmos que requieren que el estado mutable sea rápido. Pero las variables son inherentemente imperativas, explicando cómo en lugar de qué , y dando poca predicción de cuál puede ser su valor unas pocas líneas más tarde o después de algunas iteraciones de bucle. Los bucles generalmente requieren que el estado tenga sentido, por lo que también son inherentemente imperativos.
Las variables y los bucles simplemente no son programación funcional.
Resumen
La programación funcional contemporánea es un poco más de estilo y una forma útil de pensar que un paradigma. Esta mentalidad tiene una fuerte preferencia por las funciones puras, pero en realidad es solo una pequeña parte.
Los lenguajes más extendidos le permiten usar algunas construcciones funcionales. Por ejemplo, en Python puede elegir entre:
result = 0
for num in numbers:
if pred(result):
result += num
return result
o
return sum(filter(pred, numbers))
o
return sum(n for n in numbers if pred(n))
Estas expresiones funcionales se ajustan bien a ese tipo de problemas y simplemente acortan el código (y más corto es bueno ). No debe reemplazar irremediablemente el código imperativo con ellos, pero cuando encajan, casi siempre son una mejor opción.
item
variable muta en el bucle.