La respuesta corta es: todo se compila al final en un lenguaje de bajo nivel (ensamblado o lenguaje de máquina virtual). Los lenguajes funcionales e imperativos están en pie de igualdad: tienen que compilar sus mecanismos de abstracción para adaptarse a lo que está disponible en la máquina.
Donde el idioma marca la diferencia es qué tan cerca coinciden con el código subyacente de bajo nivel (proporcionando características de bajo nivel para optimizar el código a mano cuando sea conveniente) y qué optimizaciones permiten o facilitan teniendo una semántica limpia que proporciona fuertes garantías de razonamiento .
Por ejemplo, cuando se compila con código nativo, la recursión no se compila (en general) en bucles, sino en saltos a etiquetas, como lo hacen los bucles: la mayoría de los lenguajes ensamblados no tienen bucles ni recursión. Por supuesto, si compila en una máquina virtual que tiene bucles pero no salta, necesita producir bucles; esto es un problema, por ejemplo, en la Máquina Virtual de Java, porque las llamadas de cola generales son más expresivas que los bucles solos y debe evitar esa limitación, renunciando a cierta eficiencia.
Las "ventajas" de los programas funcionales pueden ser que debido a que la semántica se comporta mejor, puede razonar más fácilmente sobre el programa y, por ejemplo, expresar optimizaciones de una manera más simple. Actualmente, muchos compiladores usan el formulario intermedio Single Static Assignment (SSA), que es básicamente un lenguaje funcional de bajo nivel¹, aunque fue descubierto de forma independiente por personas de la comunidad del compilador. La mayoría de las optimizaciones son más fáciles de hacer cuando se han eliminado las mutaciones variables, por ejemplo, y una variable mantiene el mismo valor en todo su alcance. Existen algunas técnicas para registrar la asignación en more efficient ways en dichas formas intermedias funcionales.
¹: Vea el artículo corto 1998 de Andrew Appel: SSA is Functional Programming; Si está interesado en detalles sobre el formulario de SSA, aquí están some reading notes sobre la relación entre SSA y otras formas intermedias funcionales, como CPS.
También puede obtener ventajas de optimización a partir de la pureza (la ausencia de efectos secundarios, o al menos un buen control en el que el cálculo será libre de efectos secundarios) y el tipado estático. De la pureza puede derivar optimizaciones potentes como deforestation o fusion (eliminando las estructuras de datos intermedias), y al escribir puede obtener fuertes garantías sobre la forma de sus valores (es por eso que algunos lenguajes dinámicos intentan permitir algunas anotaciones de tipo restringido para la optimización fines) que permiten generar un mejor código.
En lo que respecta al acceso a las características de bajo nivel: Fortran, C y C++ son probablemente los mejores, y más ampliamente disponibles, "pueden ir a muy bajo nivel".Algunos lenguajes intentan proporcionar algunas de esas capacidades: por ejemplo ATS (originalmente un lenguaje de programación funcional, aunque es tan simple que es bastante difícil de ver) proporciona un buen control en la asignación de pila asignación-pila-asignación, ambos Haskell y the CLR (C#,etc.) proporcionan unboxed los tipos compuestos como un caso especial de dicho razonamiento de bajo nivel, y de manera similar, Rust está tratando de proporcionarle formas de tomar decisiones de bajo nivel sobre el consumo de memoria.
Sin embargo, aunque esto es ciertamente útil cuando se ha aislado una pequeña sección de código que es crítica para sus actuaciones, y se desea optimizar al máximo (renunciando a cierta flexibilidad/simplicidad/mantenibilidad), esto no cambiará su vida en situaciones cotidianas, a menos que sea un programador incrustado/kernel. Probablemente obtendrá un mayor rendimiento general de un lenguaje productivo que le permite usar el nivel de abstracción correcto y dedicar más tiempo a elegir el diseño correcto y los algoritmos para su problema. Por supuesto, uno podría querer tener ambos, y es posible pero difícil.
¿Qué quiere decir con ventajas que se abren camino hacia el intérprete? – sepp2k
@ sepp2k Al igual que los ejemplos específicos que enumeré: parece haber varias características comunes de los lenguajes de programación funcionales. Quiero saber si estas características que parecen diferenciar la programación funcional del estilo imperativo realmente marcarán alguna diferencia en el tiempo de ejecución, o es solo una diferencia más superficial en el estilo de codificación que diferencia a los dos. ¿Tener sentido? –
Cambié el título y un poco de la pregunta, espero que esté más claro ahora. –