¿Por qué la programación funcional aún no se ha hecho cargo?

197

He leído algunos textos sobre programación declarativa / funcional (lenguajes), probé Haskell y también escribí uno. Por lo que he visto, la programación funcional tiene varias ventajas sobre el estilo imperativo clásico:

  • Programas apátridas; Sin efectos secundarios
  • Concurrencia; Juega extremadamente bien con la creciente tecnología de múltiples núcleos
  • Los programas suelen ser más cortos y, en algunos casos, más fáciles de leer.
  • La productividad aumenta (ejemplo: Erlang)

  • La programación imperativa es un paradigma muy antiguo (que yo sepa) y posiblemente no sea adecuado para el siglo XXI.

¿Por qué las empresas que usan o los programas escritos en lenguajes funcionales siguen siendo tan "raros"?

¿Por qué, cuando observamos las ventajas de la programación funcional, seguimos usando lenguajes de programación imperativos?

Tal vez fue demasiado temprano para eso en 1990, ¿pero hoy?

pankrax
fuente
1
NOTA: esta pregunta ha sido discutida en meta al menos dos veces, y el consenso es que debe mantenerse, aunque archivada a través del bloqueo de "importancia histórica" ​​mencionado anteriormente. Recomiendo encarecidamente que cualquiera que vea esto con la intención de desbloquearlo se detenga y agradezca por no tener que participar en otra discusión tediosa sobre esta pregunta, disfrutar de las respuestas tal como son y continuar con sus asuntos.
Shog9

Respuestas:

530

Porque todas esas ventajas también son desventajas.

Programas apátridas; Sin efectos secundarios

Los programas del mundo real tienen que ver con los efectos secundarios y la mutación. Cuando el usuario presiona un botón es porque quiere que algo suceda. Cuando escriben algo, quieren que ese estado reemplace cualquier estado que solía estar allí. Cuando Jane Smith en contabilidad se casa y cambia su nombre a Jane Jones, es mejor que la base de datos que respalda el proceso comercial que imprime su cheque de pago se trata de manejar ese tipo de mutación. Cuando disparas la ametralladora al alienígena, la mayoría de las personas no modelan mentalmente eso como la construcción de un nuevo alienígena con menos puntos de vida; modelan eso como una mutación de las propiedades de un extraterrestre existente.

Cuando los conceptos del lenguaje de programación funcionan fundamentalmente contra el dominio que se está modelando, es difícil justificar el uso de ese lenguaje.

Concurrencia; Juega extremadamente bien con la creciente tecnología de múltiples núcleos

El problema simplemente se resuelve. Con estructuras de datos inmutables, tiene una seguridad de subprocesos barata a costa de posiblemente trabajar con datos obsoletos. Con estructuras de datos mutables, tiene la ventaja de trabajar siempre en datos nuevos a costa de tener que escribir una lógica complicada para mantener los datos consistentes. No es que uno de esos sea obviamente mejor que el otro.

Los programas suelen ser más cortos y, en algunos casos, más fáciles de leer.

Excepto en los casos en que son más largos y difíciles de leer. Aprender a leer programas escritos en un estilo funcional es una habilidad difícil; la gente parece ser mucho mejor para concebir los programas como una serie de pasos a seguir, como una receta, más que como una serie de cálculos a realizar.

La productividad aumenta (ejemplo: Erlang)

La productividad tiene que subir mucho para justificar el gasto masivo de contratar programadores que saben programar en un estilo funcional.

Y recuerde, no desea tirar un sistema de trabajo; la mayoría de los programadores no están construyendo nuevos sistemas desde cero, sino que mantienen los sistemas existentes, la mayoría de los cuales fueron construidos en lenguajes no funcionales. Imagínese tratando de justificar eso a los accionistas. ¿Por qué descartó su sistema de nómina de trabajo existente para construir uno nuevo a costa de millones de dólares? "Porque la programación funcional es increíble" es poco probable que deleite a los accionistas.

La programación imperativa es un paradigma muy antiguo (que yo sepa) y posiblemente no sea adecuado para el siglo XXI.

La programación funcional también es muy antigua. No veo cómo la edad del concepto es relevante.

No me malinterpretes. Me encanta la programación funcional, me uní a este equipo porque quería ayudar a traer conceptos de la programación funcional a C #, y creo que programar en un estilo inmutable es el camino hacia el futuro. Pero la programación en un estilo funcional tiene enormes costos que no se pueden descartar. El cambio hacia un estilo más funcional va a suceder lenta y gradualmente durante décadas. Y eso es lo que será: un cambio hacia un estilo más funcional, no una aceptación general de la pureza y belleza de Haskell y el abandono de C ++.

Construyo compiladores para vivir y definitivamente estamos adoptando un estilo funcional para la próxima generación de herramientas de compilación. Esto se debe a que la programación funcional es fundamentalmente una buena combinación para el tipo de problemas que enfrentamos. Nuestros problemas tienen que ver con tomar información en bruto (cadenas y metadatos) y transformarlos en diferentes cadenas y metadatos. En situaciones en las que ocurren mutaciones, como si alguien estuviera escribiendo en el IDE, el espacio del problema se presta inherentemente a técnicas funcionales como la reconstrucción incremental solo de las partes del árbol que cambiaron. Muchos dominios no tienen estas buenas propiedades que los hacen evidentemente susceptibles a un estilo funcional .

Eric Lippert
fuente
41
"Cuando Jane Smith en contabilidad se casa y cambia su nombre a Jane Jones, es mejor que la base de datos que respalda el proceso comercial que imprime su cheque de pago se trate de manejar ese tipo de mutación". Habrá un registro del antiguo nombre de Jane Smith, no actualizamos retroactivamente todas las instancias del antiguo nombre de Jane a su nuevo nombre;)
Juliet
40
@Juliet: Claro. Mi punto es que si tiene un objeto que representa a un empleado, tiene sentido pensar que la operación "cambiar el nombre del empleado" es una mutación del objeto que representa al empleado que no cambia la identidad del objeto . Cuando Jane Smith cambia su nombre, no crea un empleado diferente llamado Jane Jones, que de otro modo es el mismo. No hay dos empleados con dos nombres diferentes. Es natural modelar este proceso como una mutación de un objeto, no como la construcción de un nuevo objeto.
Eric Lippert
24
Esta es una buena respuesta, pero creo que a veces exageras tu caso. Como dijo Juliet, aunque la gente podría pensar que es un cambio de nombre, en realidad es un reemplazo de nombre en un nivel más profundo. Y aunque los programas funcionales pueden ser más difíciles de leer para las personas (porque es una habilidad aprendida), eso no es generalmente porque son más largos. Un programa Haskell casi siempre será más conciso que, por ejemplo, un programa Java, incluso en un dominio de "ajuste incorrecto" con mucho estado inherente.
Chuck
29
+1 Fue un soplo de aire fresco leer esta respuesta. Fantástico escuchar tal pragmatismo (con una pasión subyacente por la programación funcional) de alguien en su posición.
Dhaust
11
"Porque todas esas ventajas también son desventajas. Programas sin estado; sin efectos secundarios": Por lo que entiendo (no sé lo suficiente sobre FP para escribir una respuesta autorizada), esto no es correcto . La programación funcional se trata de transparencia referencial, no de evitar el estado (a pesar de que el estado debe manejarse adecuadamente para garantizar la transparencia referencial). Haskell permite el estado y la mutación. Simplemente proporciona diferentes herramientas (se podría argumentar, mejor) para razonar sobre ello.
Giorgio
38

Mentes maestras de la programación: conversaciones con los creadores de los principales lenguajes de programación

[Haskell]

¿Por qué crees que ningún lenguaje de programación funcional ha entrado en la corriente principal?

John Hughes: ¡ Mala comercialización! No me refiero a la propaganda; Hemos tenido mucho de eso. Me refiero a una elección cuidadosa de un nicho de mercado objetivo para dominar, seguido de un esfuerzo decidido para hacer que la programación funcional sea, con mucho, la forma más efectiva de abordar ese nicho. En los felices días de los años 80, pensamos que la programación funcional era buena para todo, pero llamar a la nueva tecnología "buena para todo" es lo mismo que llamarla "particularmente buena para nada". ¿Qué se supone que es la marca? Este es un problema que John Launchbury describió muy claramente en su charla invitada en ICFP. Galois Connections casi se vino abajo cuando su marca era "software en lenguajes funcionales", pero han ido fortaleciéndose desde que se centraron en el "software de alta seguridad".

Muchas personas no tienen idea de cómo ocurre la innovación tecnológica y esperan que una tecnología mejor se vuelva dominante por sí sola (el efecto de "mejor trampa para ratones" ), pero el mundo simplemente no es así.

Nick Dandoulakis
fuente
36
Haskell: después de 20 años, ¡un éxito de la noche a la mañana!
Julieta
sigue el enlace y lee las reseñas para ver una versión bastante divertida de Grady Booch. No tengo idea de quién es Booch, pero de todos modos me hizo reír.
fearofawhackplanet
44
Grady Booch es responsable, en última instancia, junto con Jacobson y Rumbaugh, de la abominación que es UML.
SOLO MI OPINIÓN correcta
27

La respuesta común es que ninguno de los dos debería reemplazar al otro: son herramientas diferentes que tienen diferentes conjuntos de pros y contras, y qué enfoque tiene la ventaja diferirá según el proyecto y otros problemas "blandos" como el grupo de talentos disponible.

Creo que tiene razón en que el crecimiento de la concurrencia debido a múltiples núcleos aumentará el porcentaje (del conjunto global de proyectos de desarrollo) cuando se elige la programación funcional sobre otros estilos.

Creo que es raro hoy porque la mayoría del grupo de talentos profesionales de hoy se siente más cómodo con tecnologías imperativas y orientadas a objetos. Por ejemplo, más de una vez elegí Java como lenguaje para un proyecto comercial porque era lo suficientemente bueno, no controvertido, y sé que nunca me quedaré sin personas que puedan programar (lo suficientemente bien) en él.

GRAMO__
fuente
Esto es muy perspicaz y deliciosamente pragmático. Definitivamente la mejor respuesta que he visto a esta pregunta en todas sus formas.
Benson
Tal vez por un idioma para el que ambos sean ciudadanos de primera clase se haga popular.
Kevin Kostlan
1
De acuerdo 110%. En varias ocasiones, intenté ingresar a FP, pero perdí la voluntad de continuar después de algunas semanas. Llevo más de 30 años programando procedimientos y estoy demasiado acostumbrado a la programación imperativa. Esto es cierto para la industria de TI en general. El cambio no vendrá fácil ni rápidamente.
Richard Eng
26

A pesar de las ventajas de la programación funcional, la programación imperativa y orientada a objetos nunca desaparecerá por completo.

La programación imperativa y orientada a objetos es una descripción paso a paso del problema y su solución. Como tal, puede ser más fácil de comprender. La programación funcional puede ser un poco oscura.

En última instancia, un programa útil siempre tendrá efectos secundarios (como proporcionar una salida real al usuario para el consumo), por lo que los lenguajes funcionales más puros aún necesitarán una forma de ingresar al mundo imperativo de vez en cuando.

El estado actual de la técnica es que los lenguajes imperativos (como C #) toman prestadas características del mundo funcional (como las declaraciones lambda) y viceversa.

Robert Harvey
fuente
3
¿No es OOP algún tipo de subconjunto de programación imperativa?
pankrax
9
OOP es un superconjunto. OOP es imprescindible como C ++ es para C.
Robert Harvey
10
No creo que OOP dependa necesariamente de la programación imperativa. Mire un Clojure o CLOS: ambos son funcionales, pero están orientados a objetos.
Gabe
9
Los idiomas OO tienden a ser imperativos, pero no tienen que serlo. OCaml es un lenguaje fuertemente funcional (aunque no puramente) cuya razón de ser es OO.
Chuck
77
No entiendo por qué OOP es un superconjunto de programación imperativa. No todo el código imperativo es OOP, y no todo el código funcional no es OOP. Prefiero decir que OOP es una programación imperativa y funcional como las alas aerodinámicas son para autos de carreras, o aviones, o cohetes, o ventiladores de enfriamiento, o molinos de viento, o ... es decir, los conceptos están relacionados, pero no están estrechamente unidos. Una conexión 1 a 1.
Sebastian Mach
21

¿No es así?

Smalltalk fue un gran sistema orientado a objetos en el pasado. ¿Por qué no se ha hecho cargo de la programación orientada a objetos? Pues sí. Simplemente no se parece a Smalltalk. Los lenguajes principales se vuelven cada vez más parecidos a Smalltalk con C ++, Java, C #, etc. La moda y el estilo cambian más lentamente que nada, por lo que cuando OO se generalizó, lo conseguimos pegando partes de OO a idiomas antiguos para que pareciera lo suficiente como para tragar C .

Funcional es de la misma manera. Haskell era un gran lenguaje funcional. Pero hoy tenemos más masa de programadores que usan sintaxis tipo C que hace 20 años. Por lo tanto, debe parecerse a C. Hecho: observe cualquier expresión de LINQ y dígame que no es funcional.

Conocido
fuente
2
Punto interesante, pero ¿cómo han sido los lenguajes convencionales cada vez más parecidos a Smalltalk? C ++, Java y C #, por ejemplo, no se basan en el envío de mensajes, que (creo) es la parte más importante del paradigma Smalltalk.
Jonathan Sterling
44
Jonathan: elija cualquier característica de Smalltalk y observe cómo es más débil en C ++ (la más antigua), OK en Java y mejor en C #. Por ejemplo, GC (solo Java / C #), autoboxing (más tarde Java / C # solamente), cierres (solo C #) y reflexión (presente en Java, mejor en C #). Si desea pasar mensajes, mire C # 4 dynamic. Esa es la más pequeña de estas características, por lo que no me sorprende que solo esté presente en la última versión del más moderno de estos tres idiomas. :-)
Ken
Javascript, Python y Ruby son buenas ilustraciones de cómo es realmente
nafg
15

Creo que los idiomas imperativos son más frecuentes simplemente porque a eso están acostumbrados más personas. Ni la programación funcional ni el modelo de programación imperativo son más oscuros o académicos que el otro. De hecho, son complementos.

Un cartel decía que el código imperativo es más fácil de entender que el código de programación funcional. Esto solo es cierto si el lector ya ha visto el código imperativo, especialmente si los ejemplos anteriores son parte de la misma "familia" (por ejemplo, C / C ++, Perl, PHP y Java). No diría que es cierto para cualquier lenguaje imperativo; tome una comparación de Java y Forth, para hacer un ejemplo extremo.

Para un laico, todos los lenguajes de programación son galimatías indescifrables, excepto quizás los lenguajes detallados como Hypertalk y SQL. (Cabe destacar que SQL es un lenguaje declarativo y / o funcional y goza de una enorme popularidad).

Si hubiéramos sido entrenados inicialmente en un lenguaje Lisp-y o Haskell-y desde el principio, todos pensaríamos que los lenguajes de programación funcionales son perfectamente normales.

Barry Brown
fuente
"Un afiche dijo que el código imperativo es más fácil de entender que el código de programación funcional. Esto solo es cierto si el lector ya ha visto el código imperativo, especialmente si los ejemplos anteriores son parte de la misma" familia "(por ejemplo, C / C ++, Perl, PHP y Java). ": Muy cierto (+1): Recuerdo cuánto esfuerzo tuve que hacer para aprender Pascal y C cuando comencé a programar. Y qué fácil es leer Scala, Haskell o Scheme ahora que tengo algo de experiencia con estos idiomas.
Giorgio
2
La única razón por la que todavía considero que el estado mutable a veces es útil es que ofrece una manera fácil de escribir código rápido (sin copia); pero la razón de esto podría ser que no conozco suficiente programación funcional y que, en el 90% de las situaciones, puede escribir código funcional rápido sin usar el estado mutable.
Giorgio
3
Uno de los entornos más utilizados y de larga duración para organizar la computación es la hoja de cálculo; esencialmente un entorno de programación funcional con celdas en lugar de variables con nombre. No creo que las personas, en general, conciban inherentemente los programas como una serie de pasos. Los programadores inmersos en lenguajes imperativos generalizados, tal vez.
jpnp
14

Ya has recibido suficientes respuestas que mencionaré solo un par de cosas que aún no veo mencionadas.

Primero y (en mi opinión) lo más importante, los lenguajes de procedimiento se han beneficiado enormemente de su grado de coincidencia. Por ejemplo, casi cualquier persona que conozca casi todos los lenguajes de procedimiento (u OO) convencionales en casi cualquier grado puede leer la mayoría de los demás razonablemente bien. Evito activamente trabajar en Java, C #, Cobol, Fortran o Basic (por solo algunos ejemplos), pero puedo leer cualquiera de ellos razonablemente bien, de hecho, casi tan bien como las personas que los usan todos los días.

En el lado funcional, eso es mucho menos cierto. Solo por ejemplo, también puedo escribir Scheme de manera bastante razonable, pero eso es de poca utilidad para leer Ocaml o Haskell (solo por un par de ejemplos). Incluso dentro de una sola familia (p. Ej., Scheme vs., Common Lisp) la familiaridad con uno no parece traducirse tan bien al otro.

La afirmación de que el código funcional es más legible tiende a ser verdad solo bajo un rango estrecho de condiciones. Para las personas que están extremadamente familiarizadas con el lenguaje, la legibilidad es realmente excelente, pero para todos los demás, a menudo es casi inexistente. Peor aún, si bien las diferencias en los lenguajes de procedimiento son en gran medida de sintaxis y, por lo tanto, se aprenden con relativa facilidad, las diferencias en los lenguajes funcionales a menudo son mucho más fundamentales, por lo que requieren un estudio considerable para comprender realmente (por ejemplo, saber que Lisp es de poca ayuda para comprender a las mónadas).

El otro punto importante es que la idea de que los programas funcionales son más cortos que los de procedimiento a menudo se basa más en la sintaxis que en la semántica. Los programas escritos en Haskell (por ejemplo) son a menudo bastante cortos, pero su funcionalidad es una parte bastante pequeña de eso. Una gran oferta si es simplemente que Haskell tiene una sintaxis relativamente breve.

Pocos lenguajes puramente funcionales pueden competir bien con APL por el código fuente conciso (aunque, para ser justos, APL también admite la creación de funciones de nivel superior, por lo que esa no es una gran diferencia como en otros casos). Por el contrario, Ada y C ++ (solo para un par de ejemplos) pueden ser bastante competitivos en términos del número de operaciones necesarias para realizar una tarea determinada, pero la sintaxis es (al menos generalmente) sustancialmente más detallada.

Jerry Coffin
fuente
Excelente comentario! Estoy totalmente de acuerdo. Encuentro que la mayoría de los lenguajes de procedimiento son bastante fáciles de leer y entender, aunque solo soy un experto de buena fe en algunos de ellos. No puedo decir lo mismo sobre los lenguajes FP.
Richard Eng
1
Otro punto importante es que, en cualquier paradigma dado, encontrará una gama de experiencia, desde novatos hasta gurús. El código FP puede ser fácilmente legible y comprensible para los expertos, pero los programadores intermedios aún pueden tener dificultades. Los expertos generalmente comprenden una fracción muy pequeña de la comunidad FP.
Richard Eng
11

Sin necesidad percibida

Recuerdo la respuesta de mi viejo jefe Rick Cline cuando le mostré una copia de la conferencia del Premio Turing de John Backus titulada ¿Se puede liberar la programación del estilo von Neumann?

Su respuesta: "¡Quizás algunos de nosotros no queremos ser liberados del estilo von Neumann!"

Mark Harrison
fuente
10

¿Por qué la programación funcional aún no se ha hecho cargo?

Funcional es mejor para algunas cosas y peor para otras, por lo que nunca "se hará cargo". Sin embargo, ya es omnipresente en el mundo real.

Programas apátridas; Sin efectos secundarios

Los programas sin estado son más fáciles de probar. Esto ahora es muy apreciado y a menudo explotado en la industria.

Concurrencia; Juega extremadamente bien con la creciente tecnología de múltiples núcleos Los programas suelen ser más cortos y, en algunos casos, más fáciles de leer La productividad aumenta (ejemplo: Erlang)

Estás combinando concurrencia y paralelismo.

La concurrencia se puede hacer de manera efectiva utilizando procesos secuenciales de comunicación (CSP). El código dentro de un CSP puede mutar su estado local, pero los mensajes enviados entre ellos siempre deben ser inmutables.

La programación puramente funcional juega muy mal con el multinúcleo porque es muy poco amigable con el caché. Los núcleos terminan compitiendo por la memoria compartida y los programas paralelos no escalan.

¿Por qué las empresas que usan o los programas escritos en lenguajes funcionales siguen siendo tan "raros"?

Scala a menudo se considera un lenguaje funcional, pero no es más funcional que C #, que es uno de los lenguajes más populares en el mundo de hoy.

¿Por qué, cuando observamos las ventajas de la programación funcional, seguimos usando lenguajes de programación imperativos?

La programación puramente funcional tiene muchas desventajas serias, por lo que utilizamos lenguajes funcionales impuros como Lisp, Scheme, SML, OCaml, Scala y C #.

Jon Harrop
fuente
7

Cuando pienso en lo que la programación funcional podría aportar a mis proyectos en el trabajo, siempre me guían por el mismo camino de pensamiento:

  1. Para obtener todas las ventajas de la programación funcional, necesita pereza. Sí, hay lenguajes funcionales estrictos, pero los beneficios reales de la programación funcional no brillan tan bien en un código estricto. Por ejemplo, en Haskell es fácil crear una secuencia de operaciones diferidas en una lista y concatenarlas y aplicarlas a una lista. P.ej. op1 $ op2 $ op3 $ op4 $ someList. Sé que no va a construir la lista completa e internamente solo voy a obtener un buen ciclo que recorre los elementos uno por uno. Esto le permite escribir código realmente modular. La interfaz entre dos módulos puede implicar la entrega de estructuras de datos potencialmente vastas y, sin embargo, no es necesario que la estructura resida.

  2. Pero cuando tienes pereza, se vuelve difícil razonar sobre el uso de la memoria. Cambiar los indicadores del compilador de Haskell con frecuencia cambia la cantidad de memoria utilizada por un algoritmo de O (N) a O (1), excepto que a veces no lo hace. Esto no es realmente aceptable cuando tiene aplicaciones que necesitan aprovechar al máximo toda la memoria disponible, y no es excelente incluso para aplicaciones que no necesitan toda la memoria.

sigfpe
fuente
La pereza también interactúa menos que idealmente con la depuración.
Brian
3
Como descubro que muchos de los errores que persigo en otros idiomas están relacionados con la falta de transparencia referencial, estoy menos preocupado por los problemas de depuración, aunque a veces pueden ser un problema.
sigfpe
6

Dos cosas:

  1. Solo lleva tiempo, no importa cuán buena sea una tecnología. Las ideas detrás de FP tienen aproximadamente 70 años. Pero su uso principal en Ingeniería de Software (en las trincheras, en la industria) es probablemente menos de 10 años. Pedir a los desarrolladores que adopten una mentalidad racialmente nueva es posible, pero solo lleva tiempo (muchos, muchos años). Por ejemplo, OOP realmente tuvo un uso generalizado a principios de la década de 1980. Sin embargo, no ganó latencia hasta finales de los años noventa.
  2. Necesita que las personas se vean obligadas a enfrentar la fuerza de una tecnología antes de que llegue a lo grande . Actualmente, las personas están utilizando herramientas que no utilizan el paralelismo y las cosas funcionan bien. Cuando las aplicaciones que no usan paralelismo se vuelven insoportablemente lentas; entonces muchas personas se verán obligadas a usar herramientas de paralelismo y FP puede aumentar su popularidad. Esto también puede aplicarse a otras fortalezas de FP.
Phil
fuente
3
FP es muy bueno en la reutilización de código. Probablemente mejor que OO. Tuve que lidiar con eso en el trabajo varias veces, migrar a diferentes tipos y a un nuevo sistema y fue indoloro.
nlucaroni
@Freddy Rios y @nlucaroni. Reescribí el comentario para aclarar la mala interpretación.
Phil