Es difícil definir exactamente qué es un "lenguaje funcional": de los idiomas que enumeró, solo Haskell es puramente funcional (todos los demás adoptan algún tipo de enfoque híbrido). Sin embargo, hay ciertas características de lenguaje que son muy útiles para la programación funcional, y Ruby y Python no tienen suficientes para ser entornos muy buenos para FP. Aquí está mi lista de verificación personal, en orden de importancia:
- Funciones y cierres de primera clase (Ruby, Python y todos los demás que enumeró tienen esto).
- Optimización garantizada de llamadas de cola (Erlang, Haskell, Scala y Scheme tienen esto, pero no Python, Ruby o Clojure (todavía)).
- Soporte para la inmutabilidad en el lenguaje y las bibliotecas estándar (este es uno de los grandes que tienen todos los "lenguajes funcionales" que enumeró (excepto Scheme) pero Ruby y Python no lo tienen).
- Soporte a nivel de lenguaje para funciones referencialmente transparentes (o puras) (que yo sepa, solo Haskell tiene esto actualmente).
La necesidad de (1) debería ser obvia: las funciones de orden superior son extremadamente difíciles sin funciones de primera clase. Cuando la gente habla de que Ruby y Python son buenos lenguajes para FP, generalmente hablan de esto. Sin embargo, esta característica particular es necesaria pero no suficiente para hacer que un lenguaje sea bueno para FP.
(2) ha sido una necesidad tradicional para FP desde que se inventó el Scheme. Sin TCO, es imposible programar con una recursión profunda, que es una de las piedras angulares de FP, porque se producen desbordamientos de pila. El único lenguaje "funcional" (por definición popular) que no tiene esto es Clojure (debido a las limitaciones de la JVM), pero Clojure tiene una variedad de hacks para simular el TCO. (Para su información, Ruby TCO es específico de la implementación , pero Python específicamente no lo admite ). La razón por la que debe garantizarse el TCO es que si es específica de la implementación, las funciones recursivas profundas se romperán con algunas implementaciones, por lo que no puede realmente úsalos en absoluto.
(3) es otra gran cosa que los lenguajes funcionales modernos (especialmente Haskell, Erlang, Clojure y Scala) tienen que Ruby y Python no tienen. Sin entrar en demasiados detalles, la inmutabilidad garantizada elimina clases enteras de errores, especialmente en situaciones concurrentes, y permite cosas claras como estructuras de datos persistentes . Es muy difícil aprovechar estos beneficios sin soporte de nivel de idioma.
(4) es, para mí, lo más interesante de los lenguajes puramente funcionales (a diferencia de los lenguajes híbridos). Considere la siguiente función de Ruby extremadamente simple:
def add(a, b)
a + b
end
Esto parece una función pura, pero debido a la sobrecarga del operador, podría mutar cualquiera de los parámetros o causar efectos secundarios como imprimir en la consola. Es poco probable que alguien sobrecargue al +operador para tener un efecto secundario, pero el lenguaje no ofrece garantías. (Lo mismo se aplica a Python, aunque tal vez no con este ejemplo específico).
En un lenguaje puramente funcional, por otro lado, existen garantías a nivel de lenguaje de que las funciones son referencialmente transparentes. Esto tiene numerosas ventajas: las funciones puras se pueden memorizar fácilmente; se pueden probar fácilmente sin depender de ningún tipo de estado global; y los valores dentro de la función pueden evaluarse perezosamente o en paralelo sin preocuparse por los problemas de concurrencia. Haskell aprovecha al máximo esto, pero no sé lo suficiente sobre otros lenguajes funcionales para saber si lo hacen.
Dicho todo esto, es posible utilizar técnicas de FP en casi cualquier lenguaje (incluso Java). Por ejemplo, MapReduce de Google está inspirado en ideas funcionales, pero que yo sepa, no usan ningún lenguaje "funcional" para sus grandes proyectos (creo que usan principalmente C ++, Java y Python).