Articulo de referencia

Programación funcional

En informática , la programación funcional es un paradigma de programación donde los programas se construyen aplicando y componiendo funciones . Es un paradigma de programación ...

Escucha este artículo

En informática , la programación funcional es un paradigma de programación donde los programas se construyen aplicando y componiendo funciones . Es un paradigma de programación declarativa en el que las definiciones de funciones son árboles de expresiones que asignan valores a otros valores, en lugar de una secuencia de instrucciones imperativas que actualizan el estado de ejecución del programa.

En la programación funcional, las funciones se tratan como entidades de primera clase , lo que significa que se les puede asignar un nombre (incluidos los identificadores locales ), pasarlas como argumentos y devolverlas desde otras funciones, al igual que cualquier otro tipo de dato . Esto permite escribir programas de forma declarativa y componible , donde las funciones pequeñas se combinan de manera modular .

La programación funcional a veces se considera sinónimo de programación puramente funcional , un subconjunto de la programación funcional que trata todas las funciones como funciones matemáticas deterministas o funciones puras . Cuando se llama a una función pura con ciertos argumentos, siempre devolverá el mismo resultado y no puede verse afectada por ningún estado mutable ni otros efectos secundarios . Esto contrasta con los procedimientos impuros , comunes en la programación imperativa , que pueden tener efectos secundarios (como modificar el estado del programa o recibir datos del usuario). Los defensores de la programación puramente funcional afirman que, al restringir los efectos secundarios, los programas pueden tener menos errores , ser más fáciles de depurar y probar , y ser más adecuados para la verificación formal . [ 1 ] [ 2 ]

La programación funcional tiene sus raíces en el ámbito académico, evolucionando a partir del cálculo lambda , un sistema formal de computación basado únicamente en funciones. Históricamente, la programación funcional ha sido menos popular que la programación imperativa, pero muchos lenguajes funcionales se utilizan hoy en día en la industria y la educación, incluyendo Common Lisp , Scheme , [ 3 ] [ 4 ] [ 5 ] [ 6 ] Clojure , Wolfram Language , [ 7 ] [ 8 ] Racket , [ 9 ] Erlang , [ 10 ] [ 11 ] [ 12 ] Elixir , [ 13 ] OCaml , [ 14 ] [ 15 ] Haskell , [ 16 ] [ 17 ] y F# . [ 18 ] [ 19 ] Lean es un lenguaje de programación funcional comúnmente utilizado para verificar teoremas matemáticos. [ 20 ] La programación funcional también es clave para algunos lenguajes que han tenido éxito en dominios específicos, como JavaScript en la Web, [ 21 ] R en estadística, [ 22 ] [ 23 ] J , K y Q en análisis financiero, y XQuery / XSLT para XML . [ 24 ] [ 25 ] Los lenguajes declarativos específicos de dominio como SQL y Lex / Yacc utilizan algunos elementos de la programación funcional, como no permitir valores mutables . [ 26 ] Además, muchos otros lenguajes de programación admiten la programación en un estilo funcional o han implementado características de la programación funcional, como C++ (desde C++11 ), C# , [ 27 ] Kotlin , [ 28 ] Perl , [ 29] PHP, [ 30 ] Python, [ 31 ] Go, [ 32 ] Rust, [ 33 ] Raku, [ 34 ] Scala, [ 35 ] yJava(desde Java 8). [ 36 ]

Historia

El cálculo lambda , desarrollado en la década de 1930 por Alonzo Church , es un sistema formal de computación basado en la aplicación de funciones . En 1937, Alan Turing demostró que el cálculo lambda y las máquinas de Turing son modelos de computación equivalentes, [ 37 ] lo que demuestra que el cálculo lambda es Turing completo . El cálculo lambda constituye la base de todos los lenguajes de programación funcional. Una formulación teórica equivalente, la lógica combinatoria , fue desarrollada por Moses Schönfinkel y Haskell Curry en las décadas de 1920 y 1930. [ 38 ]

Posteriormente, Church desarrolló un sistema más débil, el cálculo lambda de tipado simple , que extendió el cálculo lambda asignando un tipo de dato a todos los términos. [ 39 ] Esto constituye la base de la programación funcional de tipado estático.

El primer lenguaje de programación funcional de alto nivel , Lisp , fue desarrollado a finales de la década de 1950 para la serie de computadoras científicas IBM 700/7000 por John McCarthy mientras trabajaba en el Instituto Tecnológico de Massachusetts (MIT). [ 40 ] Las funciones de Lisp se definieron utilizando la notación lambda de Church, extendida con una construcción de etiquetas para permitir funciones recursivas . [ 41 ] Lisp introdujo por primera vez muchas características paradigmáticas de la programación funcional, aunque los primeros Lisp eran lenguajes multiparadigma e incorporaban soporte para numerosos estilos de programación a medida que evolucionaban nuevos paradigmas. Dialectos posteriores, como Scheme y Clojure , y ramificaciones como Dylan y Julia , buscaron simplificar y racionalizar Lisp en torno a un núcleo funcional limpio, mientras que Common Lisp fue diseñado para preservar y actualizar las características paradigmáticas de los numerosos dialectos más antiguos a los que reemplazó. [ 42 ]

El lenguaje de procesamiento de información (IPL), de 1956, se cita a veces como el primer lenguaje de programación funcional basado en computadora. [ 43 ] Es un lenguaje de estilo ensamblador para manipular listas de símbolos. Posee el concepto de generador , que equivale a una función que acepta otra función como argumento, y, dado que es un lenguaje de programación de bajo nivel , el código puede ser datos, por lo que se puede considerar que IPL tiene funciones de orden superior. Sin embargo, depende en gran medida de la estructura de lista mutable y características imperativas similares.

Kenneth E. Iverson desarrolló APL a principios de la década de 1960, descrito en su libro de 1962, A Programming Language ( ISBN). 9780471430148). APL fue la principal influencia en el FP de John Backus . A principios de la década de 1990, Iverson y Roger Hui crearon J. A mediados de la década de 1990, Arthur Whitney , quien había trabajado previamente con Iverson, creó K , que se utiliza comercialmente en las industrias financieras junto con su descendiente Q.

A mediados de la década de 1960, Peter Landin inventó la máquina SECD , [ 44 ] la primera máquina abstracta para un lenguaje de programación funcional, [ 45 ] describió una correspondencia entre ALGOL 60 y el cálculo lambda , [ 46 ] [ 47 ] y propuso el lenguaje de programación ISWIM . [ 48 ]

John Backus presentó la programación funcional en su conferencia de aceptación del Premio Turing de 1977 titulada "¿Puede liberarse la programación del estilo de von Neumann ? Un estilo funcional y su álgebra de programas". [ 49 ] Definió los programas funcionales como aquellos que se construyen de manera jerárquica mediante "formas combinables" que permiten un "álgebra de programas"; en lenguaje moderno, esto significa que los programas funcionales siguen el principio de composicionalidad . [ 50 ] El artículo de Backus popularizó la investigación en programación funcional, aunque enfatizó la programación a nivel de función en lugar del estilo de cálculo lambda que ahora se asocia con la programación funcional.

El lenguaje ML de 1973 fue creado por Robin Milner en la Universidad de Edimburgo , y David Turner desarrolló el lenguaje SASL en la Universidad de St Andrews . También en Edimburgo en la década de 1970, Burstall y Darlington desarrollaron el lenguaje funcional NPL . [ 51 ] NPL se basó en las ecuaciones de recursión de Kleene y se introdujo por primera vez en su trabajo sobre transformación de programas. [ 52 ] Burstall, MacQueen y Sannella luego incorporaron la verificación de tipos polimórficos de ML para producir el lenguaje Hope . [ 53 ] ML finalmente se desarrolló en varios dialectos, los más comunes de los cuales ahora son OCaml y Standard ML .

En la década de 1970, Guy L. Steele y Gerald Jay Sussman desarrollaron Scheme , tal como se describe en los Lambda Papers y en el libro de texto de 1985, Structure and Interpretation of Computer Programs . Scheme fue el primer dialecto de Lisp en utilizar el alcance léxico y en requerir la optimización de llamadas recursivas , características que fomentan la programación funcional.

En la década de 1980, Per Martin-Löf desarrolló la teoría de tipos intuicionista (también llamada teoría de tipos constructiva ), que asociaba programas funcionales con pruebas constructivas expresadas como tipos dependientes . Esto dio lugar a nuevos enfoques para la demostración interactiva de teoremas y ha influido en el desarrollo de lenguajes de programación funcional posteriores. [ 54 ]

El lenguaje funcional perezoso Miranda , desarrollado por David Turner, apareció inicialmente en 1985 y tuvo una gran influencia en Haskell . Dado que Miranda era un lenguaje propietario, Haskell comenzó en 1987 con un consenso para formar un estándar abierto para la investigación en programación funcional; las implementaciones se han estado publicando continuamente desde 1990.

Más recientemente, se ha utilizado en nichos como el CAD paramétrico en el lenguaje OpenSCAD basado en el marco CGAL , aunque su restricción en la reasignación de valores (todos los valores se tratan como constantes) ha generado confusión entre los usuarios que no están familiarizados con la programación funcional como concepto. [ 55 ]

La programación funcional continúa utilizándose en entornos comerciales. [ 56 ] [ 57 ] [ 58 ]

Conceptos

Varios conceptos [ 59 ] y paradigmas son específicos de la programación funcional y, en general, ajenos a la programación imperativa (incluida la programación orientada a objetos ). Sin embargo, los lenguajes de programación suelen adaptarse a varios paradigmas de programación, por lo que los programadores que utilizan lenguajes "principalmente imperativos" pueden haber utilizado algunos de estos conceptos. [ 60 ]

Funciones de primera clase y de orden superior

Las funciones de orden superior son funciones que pueden tomar otras funciones como argumentos o devolverlas como resultados. En cálculo, un ejemplo de una función de orden superior es el operador diferencial.d/dincógnita{\displaystyle d/dx}, que devuelve la derivada de una funciónF{\displaystyle f}.

Las funciones de orden superior están estrechamente relacionadas con las funciones de primera clase , ya que ambas permiten que las funciones actúen como argumentos y resultados de otras funciones. La distinción entre ambas es sutil: "orden superior" describe un concepto matemático de funciones que operan sobre otras funciones, mientras que "primera clase" es un término informático que se refiere a entidades de lenguajes de programación cuyo uso no tiene restricciones (por lo tanto, las funciones de primera clase pueden aparecer en cualquier parte del programa donde puedan aparecer otras entidades de primera clase, como los números, incluyendo como argumentos de otras funciones y como sus valores de retorno).

Las funciones de orden superior permiten la aplicación parcial o currificación , una técnica que aplica una función a sus argumentos uno a uno, de modo que cada aplicación devuelve una nueva función que acepta el siguiente argumento. Esto permite al programador expresar de forma concisa, por ejemplo, la función sucesora como el operador de suma aplicado parcialmente al número natural uno.

funciones puras

Las funciones (o expresiones) puras no tienen efectos secundarios (memoria o E/S). Esto significa que las funciones puras tienen varias propiedades útiles, muchas de las cuales se pueden usar para optimizar el código:

  • Si el resultado de una expresión pura no se utiliza, se puede eliminar sin afectar a otras expresiones.
  • Si se llama a una función pura con argumentos que no producen efectos secundarios, el resultado es constante con respecto a esa lista de argumentos (lo que a veces se denomina transparencia referencial o idempotencia ); es decir, al volver a llamar a la función pura con los mismos argumentos se obtiene el mismo resultado. (Esto puede permitir optimizaciones de caché como la memorización ).
  • Si no existe dependencia de datos entre dos expresiones puras, su orden puede invertirse o pueden ejecutarse en paralelo y no pueden interferir entre sí (en otras palabras, la evaluación de cualquier expresión pura es segura para subprocesos ).
  • Si el lenguaje completo no permite efectos secundarios, entonces se puede utilizar cualquier estrategia de evaluación; esto le da al compilador la libertad de reordenar o combinar la evaluación de expresiones en un programa (por ejemplo, utilizando la deforestación ).

Si bien la mayoría de los compiladores para lenguajes de programación imperativos detectan funciones puras y realizan la eliminación de subexpresiones comunes para llamadas a funciones puras, no siempre pueden hacerlo para bibliotecas precompiladas, que generalmente no exponen esta información, lo que impide las optimizaciones que involucran esas funciones externas. Algunos compiladores, como gcc , agregan palabras clave adicionales para que un programador marque explícitamente las funciones externas como puras, para habilitar dichas optimizaciones. Fortran 95 también permite que las funciones se designen como puras . [ 61 ] C++11 agregó constexpruna palabra clave con semántica similar.

Recursión

La iteración (bucle) en lenguajes funcionales se suele realizar mediante recursión . Las funciones recursivas se invocan a sí mismas, permitiendo que una operación se repita hasta alcanzar el caso base . En general, la recursión requiere mantener una pila , cuyo consumo de espacio es lineal con respecto a la profundidad de la recursión. Esto podría hacer que la recursión sea prohibitivamente costosa en comparación con los bucles imperativos. Sin embargo, una forma especial de recursión conocida como recursión de cola puede ser reconocida y optimizada por un compilador en el mismo código utilizado para implementar la iteración en lenguajes imperativos. La optimización de la recursión de cola puede implementarse, entre otros métodos, transformando el programa al estilo de paso de continuaciones durante la compilación.

El estándar del lenguaje Scheme requiere que las implementaciones admitan la recursión de cola adecuada, lo que significa que deben permitir un número ilimitado de llamadas de cola activas. [ 62 ] [ 63 ] La recursión de cola adecuada no es simplemente una optimización; es una característica del lenguaje que asegura a los usuarios que pueden usar la recursión para expresar un bucle y que hacerlo sería seguro para el espacio. [ 64 ] Además, contrariamente a su nombre, tiene en cuenta todas las llamadas de cola, no solo la recursión de cola. Si bien la recursión de cola adecuada generalmente se implementa convirtiendo el código en bucles imperativos, las implementaciones pueden implementarla de otras maneras. Por ejemplo, Chicken mantiene intencionalmente una pila y deja que la pila se desborde . Sin embargo, cuando esto sucede, su recolector de basura reclamará espacio nuevamente, [ 65 ] permitiendo un número ilimitado de llamadas de cola activas aunque no convierta la recursión de cola en un bucle.

Los patrones comunes de recursión pueden abstraerse mediante funciones de orden superior, siendo los catamorfismos y anamorfismos (o "pliegues" y "despliegues") los ejemplos más evidentes. Estos esquemas de recursión desempeñan un papel análogo al de las estructuras de control integradas, como los bucles en los lenguajes imperativos .

La mayoría de los lenguajes de programación funcional de propósito general permiten la recursión sin restricciones y son Turing completos , lo que hace que el problema de la parada sea indecidible , puede causar inconsistencias en el razonamiento ecuacional y, por lo general, requiere la introducción de inconsistencias en la lógica expresada por el sistema de tipos del lenguaje . Algunos lenguajes de propósito especial, como Rocq, solo permiten la recursión bien fundada y son fuertemente normalizadores (las computaciones no terminantes solo pueden expresarse con flujos infinitos de valores llamados codatos ). En consecuencia, estos lenguajes no son Turing completos y expresar ciertas funciones en ellos es imposible, pero aún pueden expresar una amplia clase de computaciones interesantes evitando los problemas introducidos por la recursión sin restricciones. La programación funcional limitada a la recursión bien fundada con algunas otras restricciones se denomina programación funcional total . [ 66 ]

Evaluación estricta versus evaluación no estricta

Los lenguajes funcionales se pueden clasificar según utilicen evaluación estricta (estricta) o no estricta (perezosa) , conceptos que se refieren a cómo se procesan los argumentos de las funciones cuando se evalúa una expresión. La diferencia técnica radica en la semántica denotacional de las expresiones que contienen cálculos fallidos o divergentes. Bajo la evaluación estricta, la evaluación de cualquier término que contenga un subtérmino fallido falla. Por ejemplo, la instrucción de Python :

imprimir ( len ([ 2 + 1 , 3 * 2 , 1 / 0 , 5 - 4 ]))

La evaluación estricta falla debido a la división por cero en el tercer elemento de la lista. En la evaluación perezosa, la función `length` devuelve el valor 4 (es decir, el número de elementos en la lista), ya que su evaluación no intenta evaluar los términos que la componen. En resumen, la evaluación estricta siempre evalúa completamente los argumentos de la función antes de invocarla. La evaluación perezosa no evalúa los argumentos de la función a menos que sus valores sean necesarios para evaluar la llamada a la función en sí.

La estrategia de implementación habitual para la evaluación perezosa en lenguajes funcionales es la reducción de grafos . [ 67 ] La evaluación perezosa se utiliza por defecto en varios lenguajes funcionales puros, incluidos Miranda , Clean y Haskell .

Hughes (1984) defiende la evaluación perezosa como un mecanismo para mejorar la modularidad de los programas mediante la separación de responsabilidades , facilitando la implementación independiente de productores y consumidores de flujos de datos. [ 2 ] Launchbury (1993) describe algunas dificultades que introduce la evaluación perezosa, particularmente en el análisis de los requisitos de almacenamiento de un programa, y ​​propone una semántica operacional para ayudar en dicho análisis. [ 68 ] Harper (2009) propone incluir tanto la evaluación estricta como la perezosa en el mismo lenguaje, utilizando el sistema de tipos del lenguaje para distinguirlas. [ 69 ]

Sistemas de tipos

Especialmente desde el desarrollo de la inferencia de tipos de Hindley-Milner en la década de 1970, los lenguajes de programación funcional han tendido a usar el cálculo lambda tipado , rechazando todos los programas inválidos en tiempo de compilación y arriesgándose a errores de falsos positivos , en contraposición al cálculo lambda sin tipado , que acepta todos los programas válidos en tiempo de compilación y arriesgándose a errores de falsos negativos , utilizado en Lisp y sus variantes (como Scheme ), ya que rechazan todos los programas inválidos en tiempo de ejecución cuando la información es suficiente para no rechazar programas válidos. El uso de tipos de datos algebraicos facilita la manipulación de estructuras de datos complejas; la presencia de una fuerte verificación de tipos en tiempo de compilación hace que los programas sean más fiables en ausencia de otras técnicas de fiabilidad como el desarrollo guiado por pruebas , mientras que la inferencia de tipos libera al programador de la necesidad de declarar manualmente los tipos al compilador en la mayoría de los casos.

Algunos lenguajes funcionales orientados a la investigación, como Rocq , Agda , Cayenne y Epigram, se basan en la teoría de tipos intuicionista , que permite que los tipos dependan de los términos. Estos tipos se denominan tipos dependientes . Estos sistemas de tipos no tienen inferencia de tipos decidible y son difíciles de comprender y programar. [ 70 ] [ 71 ] [ 72 ] [ 73 ] Pero los tipos dependientes pueden expresar proposiciones arbitrarias en lógica de orden superior . Mediante el isomorfismo de Curry-Howard , los programas bien tipados en estos lenguajes se convierten en un medio para escribir demostraciones matemáticas formales a partir de las cuales un compilador puede generar código certificado . Si bien estos lenguajes son principalmente de interés en la investigación académica (incluidas las matemáticas formalizadas ), también han comenzado a utilizarse en ingeniería. Compcert es un compilador para un subconjunto del lenguaje C que está escrito en Rocq y verificado formalmente. [ 74 ]

Una forma limitada de tipos dependientes, denominados tipos de datos algebraicos generalizados (GADT), puede implementarse de manera que proporcione algunos de los beneficios de la programación con tipos dependientes, evitando al mismo tiempo la mayoría de sus inconvenientes. [ 75 ] Los GADT están disponibles en el Glasgow Haskell Compiler , en OCaml [ 76 ] y en Scala , [ 77 ] y se han propuesto como complementos para otros lenguajes, incluidos Java y C#. [ 78 ]

Transparencia referencial

Los programas funcionales no contienen sentencias de asignación; es decir, el valor de una variable en un programa funcional nunca cambia una vez definida. Esto elimina cualquier posibilidad de efectos secundarios, ya que cualquier variable puede ser reemplazada por su valor real en cualquier punto de la ejecución. Por lo tanto, los programas funcionales son referencialmente transparentes. [ 79 ]

Consideremos la instrucción de asignación en Cx = x * 10 , que cambia el valor asignado a la variable x. Digamos que el valor inicial de xera 1, entonces dos evaluaciones consecutivas de la variable xproducen 10y 100respectivamente. Claramente, reemplazar x = x * 10con 10o 100le da al programa un significado diferente, por lo que la expresión no es referencialmente transparente. De hecho, las instrucciones de asignación nunca son referencialmente transparentes.

Ahora bien, consideremos otra función que sea transparente, ya que no modifica implícitamente la entrada x y, por lo tanto, no tiene efectos secundarios . Los programas funcionales utilizan exclusivamente este tipo de función y, por consiguiente, son referencialmente transparentes.intplusOne(intx){returnx+1;}

Estructuras de datos

Las estructuras de datos puramente funcionales a menudo se representan de manera diferente a sus contrapartes imperativas . [ 80 ] Por ejemplo, el array con tiempos de acceso y actualización constantes es un componente básico de la mayoría de los lenguajes imperativos, y muchas estructuras de datos imperativas, como la tabla hash y el montón binario , se basan en arrays. Los arrays pueden reemplazarse por mapas o listas de acceso aleatorio, que admiten una implementación puramente funcional, pero tienen tiempos de acceso y actualización logarítmicos . Las estructuras de datos puramente funcionales tienen persistencia , una propiedad que mantiene las versiones anteriores de la estructura de datos sin modificar. En Clojure, las estructuras de datos persistentes se utilizan como alternativas funcionales a sus contrapartes imperativas. Los vectores persistentes, por ejemplo, utilizan árboles para la actualización parcial. Llamar al método `insert` dará como resultado la creación de algunos nodos, pero no de todos. [ 81 ]

Comparación con la programación imperativa

La programación funcional es muy diferente de la programación imperativa . Las diferencias más significativas radican en que la programación funcional evita los efectos secundarios , que se utilizan en la programación imperativa para implementar el estado y la entrada/salida. La programación funcional pura previene por completo los efectos secundarios y proporciona transparencia referencial.

Las funciones de orden superior rara vez se utilizan en la programación imperativa tradicional. Un programa imperativo tradicional podría usar un bucle para recorrer y modificar una lista. Un programa funcional, en cambio, probablemente usaría una función de "mapeo" de orden superior que recibe una función y una lista, generando y devolviendo una nueva lista al aplicar la función a cada elemento de la lista.

Programación imperativa frente a programación funcional

Los siguientes dos ejemplos (escritos en Java ) logran el mismo efecto: multiplican todos los números pares de un array por 10 y los suman todos, almacenando la suma final en la variable result.

Bucle imperativo tradicional:

int [] numList = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; int result = 0 ; for ( int i : numList ) { if ( i % 2 == 0 ) { result += i * 10 ; } }

Programación funcional con funciones de orden superior:

import java.util.Arrays ;int [ ] numList = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 } ; int result = Arrays.stream ( numList ) .filter ( n - > n % 2 == 0 ) .map ( n - > n * 10 ) .reduce ( 0 , Integer :: sum ) ;

En ocasiones, las abstracciones que ofrece la programación funcional pueden conducir al desarrollo de un código más robusto que evita ciertos problemas que podrían surgir al construir sobre una gran cantidad de código imperativo complejo, como errores de desfase de uno (véase la décima regla de Greenspun ).

Simulando estado

Hay tareas (por ejemplo, mantener el saldo de una cuenta bancaria) que a menudo parecen implementarse de forma más natural mediante el uso de estados. La programación funcional pura realiza estas tareas, así como las tareas de entrada/salida, como aceptar la entrada del usuario e imprimir en pantalla, de una manera diferente.

El lenguaje de programación funcional puro Haskell los implementa usando mónadas , derivadas de la teoría de categorías . [ 82 ] Las mónadas ofrecen una forma de abstraer ciertos tipos de patrones computacionales, incluyendo (pero no limitándose a) el modelado de computaciones con estado mutable (y otros efectos secundarios como E/S) de manera imperativa sin perder pureza. Si bien las mónadas existentes pueden ser fáciles de aplicar en un programa, con plantillas y ejemplos apropiados, a muchos estudiantes les resulta difícil entenderlas conceptualmente, por ejemplo, cuando se les pide que definan nuevas mónadas (lo cual a veces es necesario para ciertos tipos de bibliotecas). [ 83 ]

Los lenguajes funcionales también simulan estados pasando estados inmutables. Esto se puede lograr haciendo que una función acepte el estado como uno de sus parámetros y devuelva un nuevo estado junto con el resultado, dejando el estado anterior sin cambios. [ 84 ]

Los lenguajes funcionales impuros suelen incluir un método más directo para gestionar el estado mutable. Clojure , por ejemplo, utiliza referencias gestionadas que se pueden actualizar aplicando funciones puras al estado actual. Este enfoque permite la mutabilidad a la vez que promueve el uso de funciones puras como la forma preferida de expresar cálculos. [ 85 ]

Se han desarrollado métodos alternativos, como la lógica de Hoare y la unicidad, para rastrear los efectos secundarios en los programas. Algunos lenguajes de investigación modernos utilizan sistemas de efectos para hacer explícita la presencia de efectos secundarios. [ 86 ]

Problemas de eficiencia

Los lenguajes de programación funcional suelen ser menos eficientes en su uso de CPU y memoria que los lenguajes imperativos como C y Pascal . [ 87 ] Esto se relaciona con el hecho de que algunas estructuras de datos mutables, como los arreglos, tienen una implementación muy sencilla utilizando el hardware actual. Los arreglos planos pueden ser accedidos de manera muy eficiente con CPUs con segmentación profunda, precargados eficientemente a través de cachés (sin búsqueda compleja de punteros ) o manejados con instrucciones SIMD. Tampoco es fácil crear sus contrapartes inmutables de propósito general igualmente eficientes. Para los lenguajes puramente funcionales, la ralentización en el peor de los casos es logarítmica en el número de celdas de memoria utilizadas, porque la memoria mutable puede representarse mediante una estructura de datos puramente funcional con tiempo de acceso logarítmico (como un árbol balanceado). [ 88 ] Sin embargo, tales ralentizaciones no son universales. Para programas que realizan cálculos numéricos intensivos, los lenguajes funcionales como OCaml y Clean son solo ligeramente más lentos que C según The Computer Language Benchmarks Game . [ 89 ] Para programas que manejan matrices grandes y bases de datos multidimensionales , se diseñaron lenguajes funcionales de matrices (como J y K ) con optimizaciones de velocidad.

La inmutabilidad de los datos puede, en muchos casos, conducir a una mayor eficiencia de ejecución al permitir que el compilador haga suposiciones que no son seguras en un lenguaje imperativo, aumentando así las oportunidades de expansión en línea . [ 90 ] Aunque la copia involucrada, que puede parecer implícita al tratar con estructuras de datos persistentes e inmutables, pueda parecer computacionalmente costosa, algunos lenguajes de programación funcional, como Clojure, resuelven este problema implementando mecanismos para compartir memoria de forma segura entre datos formalmente inmutables . [ 91 ] Rust se distingue por su enfoque de la inmutabilidad de datos, que implica referencias inmutables [ 92 ] y un concepto llamado tiempos de vida. [ 93 ]

Los datos inmutables con separación de identidad y estado y esquemas sin recursos compartidos también pueden ser potencialmente más adecuados para la programación concurrente y paralela debido a la reducción o eliminación del riesgo de ciertos peligros de concurrencia, ya que las operaciones concurrentes suelen ser atómicas y esto permite eliminar la necesidad de bloqueos. Así es como java.util.concurrentse implementan, por ejemplo, las clases, donde algunas de ellas son variantes inmutables de las clases correspondientes que no son adecuadas para el uso concurrente. [ 94 ] Los lenguajes de programación funcional a menudo tienen un modelo de concurrencia que en lugar de estado compartido y sincronización, aprovecha mecanismos de paso de mensajes (como el modelo de actor , donde cada actor es un contenedor para el estado, el comportamiento, los actores hijos y una cola de mensajes). [ 95 ] [ 96 ] Este enfoque es común en Erlang / Elixir o Akka .

La evaluación perezosa también puede acelerar el programa, incluso asintóticamente, mientras que puede ralentizarlo como máximo por un factor constante (sin embargo, puede introducir fugas de memoria si se usa incorrectamente). Launchbury 1993 [ 68 ] analiza cuestiones teóricas relacionadas con las fugas de memoria de la evaluación perezosa, y O'Sullivan et al. 2008 [ 97 ] ofrecen algunos consejos prácticos para analizarlas y corregirlas. Sin embargo, las implementaciones más generales de evaluación perezosa que hacen un uso extensivo de código y datos desreferenciados tienen un rendimiento deficiente en procesadores modernos con tuberías profundas y cachés multinivel (donde un fallo de caché puede costar cientos de ciclos). [ 98 ]

Costo de extracción

Algunos lenguajes de programación funcional podrían no optimizar abstracciones como funciones de orden superior como " map " o " filter " con la misma eficiencia que las operaciones imperativas subyacentes. Consideremos, por ejemplo, las dos siguientes formas de comprobar si 5 es un número par en Clojure :

(¿ igual? 5 ) ( .igual ( mod 5 2 ) 0 )

Cuando se realiza una prueba de rendimiento utilizando la herramienta Criterium en un PC Ryzen 7900X GNU/Linux en un REPL Leiningen 2.11.2, ejecutándose en la versión 22 de la máquina virtual Java y la versión 1.11.1 de Clojure, la primera implementación, que se implementa como:

( defn even? "Devuelve verdadero si n es par, lanza una excepción si n no es un entero" { :added "1.0" :static true } [ n ] ( if ( integer? n ) ( zero? ( bit-and ( clojure.lang.RT/uncheckedLongCast n ) 1 )) ( throw ( IllegalArgumentException. ( str "El argumento debe ser un entero: " n )))))

tiene un tiempo de ejecución promedio de 4,76 ms, mientras que el segundo, en el que .equalses una invocación directa del método Java subyacente , tiene un tiempo de ejecución promedio de 2,8 μs, aproximadamente 1700 veces más rápido. Parte de esto puede atribuirse a la verificación de tipos y el manejo de excepciones involucrados en la implementación de even?. Por ejemplo, la biblioteca lo para Go , que implementa varias funciones de orden superior comunes en lenguajes de programación funcional usando genéricos . En una prueba de rendimiento proporcionada por el autor de la biblioteca, la llamada mapes un 4% más lenta que un forbucle equivalente y tiene el mismo perfil de asignación , [ 99 ] lo que puede atribuirse a varias optimizaciones del compilador, como la inserción en línea . [ 100 ]

Una característica distintiva de Rust son las abstracciones de coste cero . Esto significa que su uso no impone ninguna sobrecarga adicional en tiempo de ejecución. Esto se logra gracias a que el compilador utiliza el desenrollado de bucles , donde cada iteración de un bucle, ya sea imperativo o con iteradores, se convierte en una instrucción de ensamblador independiente , sin la sobrecarga del código que controla el bucle. Si una operación iterativa escribe en un array, los elementos del array resultante se almacenarán en registros específicos de la CPU , lo que permite un acceso en tiempo constante durante la ejecución. [ 101 ]

Programación funcional en lenguajes no funcionales

Es posible utilizar un estilo de programación funcional en lenguajes que tradicionalmente no se consideran lenguajes funcionales. [ 102 ] Por ejemplo, tanto D [ 103 ] como Fortran 95 [ 61 ] admiten explícitamente funciones puras.

JavaScript , Lua , [ 104 ] Python y Go [ 105 ] tuvieron funciones de primera clase desde su inicio. [ 106 ] Python tuvo soporte para " lambda ", " map ", " reduce " y " filter " en 1994, así como cierres en Python 2.2, [ 107 ] aunque Python 3 relegó "reduce" al functoolsmódulo de la biblioteca estándar. [ 108 ] Las funciones de primera clase se han introducido en otros lenguajes principales como Perl 5.0 en 1994, PHP 5.3, Visual Basic 9 , C# 3.0, C++11 y Kotlin . [ 28 ]

En Perl, las expresiones lambda , map , reduce , filter y los cierres son totalmente compatibles y de uso frecuente. El libro Higher-Order Perl , publicado en 2005, se escribió para ofrecer una guía exhaustiva sobre el uso de Perl en la programación funcional.

En PHP, las clases anónimas , los cierres y las expresiones lambda son totalmente compatibles. Se están desarrollando bibliotecas y extensiones del lenguaje para estructuras de datos inmutables con el fin de facilitar la programación en el estilo funcional.

En Java , las clases anónimas a veces se pueden usar para simular cierres; [ 109 ] sin embargo, las clases anónimas no siempre son reemplazos adecuados para los cierres porque tienen capacidades más limitadas. [ 110 ] Java 8 admite expresiones lambda como reemplazo para algunas clases anónimas. [ 111 ]

En C# , las clases anónimas no son necesarias, ya que las clausuras y las expresiones lambda son totalmente compatibles. Se están desarrollando bibliotecas y extensiones del lenguaje para estructuras de datos inmutables con el fin de facilitar la programación funcional en C#.

Muchos patrones de diseño orientados a objetos se pueden expresar en términos de programación funcional: por ejemplo, el patrón de estrategia simplemente dicta el uso de una función de orden superior, y el patrón visitante se corresponde aproximadamente con un catamorfismo o plegado .

De manera similar, la idea de datos inmutables de la programación funcional se incluye a menudo en los lenguajes de programación imperativos, [ 112 ] por ejemplo la tupla en Python, que es un array inmutable, y Object.freeze() en JavaScript. [ 113 ]

Comparación con la programación lógica

La programación lógica puede considerarse una generalización de la programación funcional, en la que las funciones son un caso especial de las relaciones. [ 114 ] Por ejemplo, la función madre(X) = Y (cada X tiene una sola madre Y) puede representarse mediante la relación madre(X, Y). Mientras que las funciones tienen un patrón estricto de entrada-salida de argumentos, las relaciones pueden consultarse con cualquier patrón de entradas y salidas. Considere el siguiente programa lógico:

madre ( Charles , Elizabeth ). madre ( Harry , Diana ).

El programa puede consultarse, como un programa funcional, para generar madres a partir de hijos:

?- madre ( harry , X ). X = diana . ?- madre ( charles , X ). X = elizabeth .

Pero también se puede consultar hacia atrás para generar hijos:

?- madre ( X , elizabeth ). X = charles . ?- madre ( X , diana ). X = harry .

Incluso se puede utilizar para generar todas las instancias de la relación madre:

?- madre ( X , Y ). X = Carlos , Y = Isabel . X = harry , Y = diana .

En comparación con la sintaxis relacional, la sintaxis funcional es una notación más compacta para funciones anidadas. Por ejemplo, la definición de abuela materna en sintaxis funcional se puede escribir en la forma anidada:

abuela_materna ( X ) = madre ( madre ( X )).

La misma definición en notación relacional debe escribirse en forma no anidada:

abuela_materna ( X , Y ) :- madre ( X , Z ), madre ( Z , Y ).

Aquí :-significa si y , significa y .

Sin embargo, la diferencia entre las dos representaciones es simplemente sintáctica. En Ciao Prolog, las relaciones pueden anidarse, como las funciones en la programación funcional: [ 115 ]

abuelo ( X ) := padre ( padre ( X )). padre ( X ) := madre ( X ). padre ( X ) := padre ( X ).madre ( charles ) := elizabeth . padre ( charles ) := phillip . madre ( harry ) := diana . padre ( harry ) := charles .?- abuelo ( X , Y ). X = harry , Y = elizabeth . X = harry , Y = phillip .

Ciao transforma la notación de tipo función en una forma relacional y ejecuta el programa lógico resultante utilizando la estrategia de ejecución estándar de Prolog.

Aplicaciones

Editores de texto

Emacs , una familia de editores de texto altamente extensibles, utiliza su propio dialecto Lisp para escribir complementos. El autor original de la implementación más popular de Emacs, GNU Emacs y Emacs Lisp, Richard Stallman, considera a Lisp uno de sus lenguajes de programación favoritos. [ 116 ]

hojas de cálculo

Las hojas de cálculo pueden considerarse una forma de sistema de programación funcional de evaluación estricta , de orden cero y pura. [ 117 ] Sin embargo, generalmente carecen de funciones de orden superior y de reutilización de código, y en algunas implementaciones, también carecen de recursión. Se han desarrollado varias extensiones para programas de hojas de cálculo con el fin de habilitar funciones de orden superior y reutilizables, pero hasta ahora siguen siendo principalmente de carácter académico. [ 118 ]

Microservicios

Debido a su capacidad de composición , los paradigmas de programación funcional pueden ser adecuados para arquitecturas basadas en microservicios . [ 119 ]

Academia

La programación funcional es un área de investigación activa en el campo de la teoría de lenguajes de programación . Existen varias publicaciones revisadas por pares centradas en la programación funcional, como la Conferencia Internacional sobre Programación Funcional , la Revista de Programación Funcional y el Simposio sobre Tendencias en Programación Funcional .

Industria

La programación funcional se ha empleado en una amplia gama de aplicaciones industriales. Por ejemplo, Erlang , que fue desarrollado por la empresa sueca Ericsson a finales de la década de 1980, se utilizó originalmente para implementar sistemas de telecomunicaciones tolerantes a fallos , [ 11 ] pero desde entonces se ha popularizado para construir una variedad de aplicaciones en empresas como Nortel , Facebook , Électricité de France y WhatsApp . [ 10 ] [ 12 ] [ 120 ] [ 121 ] [ 122 ] Scheme , un dialecto de Lisp , se utilizó como base para varias aplicaciones en las primeras computadoras Apple Macintosh [ 3 ] [ 4 ] y se ha aplicado a problemas como software de simulación de entrenamiento [ 5 ] y control de telescopios . [ 6 ] OCaml , que se introdujo a mediados de la década de 1990, ha tenido uso comercial en áreas como análisis financiero, [ 14 ] verificación de controladores , programación de robots industriales y análisis estático de software embebido . [ 15 ] Haskell , aunque inicialmente se concibió como un lenguaje de investigación, [ 17 ] también se ha aplicado en áreas como sistemas aeroespaciales, diseño de hardware y programación web. [ 16 ] [ 17 ]

Otros lenguajes de programación funcional que se han utilizado en la industria incluyen Scala , [ 123 ] F# , [ 18 ] [ 19 ] Wolfram Language , [ 7 ] Lisp , [ 124 ] Standard ML [ 125 ] [ 126 ] y Clojure . [ 127 ] Scala se ha utilizado ampliamente en ciencia de datos , [ 128 ] mientras que ClojureScript , [ 129 ] Elm [ 130 ] o PureScript [ 131 ] son ​​algunos de los lenguajes de programación funcional frontend utilizados en producción. El framework Phoenix de Elixir también es utilizado por algunos proyectos comerciales relativamente populares, como Font Awesome o la plataforma de anuncios clasificados Allegro Lokalnie de Allegro (una de las plataformas de comercio electrónico más grandes de Polonia) . [ 132 ] [ 133 ]

Las plataformas funcionales han sido populares en finanzas para el análisis de riesgos (especialmente en grandes bancos de inversión). Los factores de riesgo se codifican como funciones que forman grafos interdependientes (categorías) para medir correlaciones en los cambios del mercado, de manera similar a las optimizaciones de la base de Gröbner, pero también para marcos regulatorios como el Análisis y Revisión Integral de Capital . Dado el uso de OCaml y sus variantes en finanzas, estos sistemas a veces se consideran relacionados con una máquina abstracta categórica . La programación funcional está fuertemente influenciada por la teoría de categorías .

Educación

Muchas universidades imparten programación funcional. [ 134 ] [ 135 ] [ 136 ] [ 137 ] Algunas la tratan como un concepto de programación introductorio [ 137 ] mientras que otras primero enseñan métodos de programación imperativa. [ 136 ] [ 138 ]

Fuera de la informática, la programación funcional se utiliza para enseñar resolución de problemas, conceptos algebraicos y geométricos. [ 139 ] También se ha utilizado para enseñar mecánica clásica, como en el libro Estructura e interpretación de la mecánica clásica .

En particular, Scheme ha sido una opción relativamente popular para la enseñanza de la programación durante años. [ 140 ] [ 141 ]

Véase también

Notas y referencias

  1. Hudak, Paul (septiembre de 1989). "Concepción, evolución y aplicación de lenguajes de programación funcional" (PDF) . ACM Computing Surveys . 21 (3): 359– 411. doi : 10.1145/72551.72554 . S2CID 207637854. Archivado del original (PDF) el 31 de enero de 2016. Recuperado el 10 de agosto de 2013 . 
  2. 1 2 Hughes, John (1984). "Por qué importa la programación funcional" .
  3. 1 2 Clinger, Will (1987). "Multitarea y MacScheme" . MacTech . 3 (12) . Recuperado el 28 de agosto de 2008 .
  4. 1 2 Hartheimer, Anne (1987). "Programación de un editor de texto en MacScheme+Toolsmith" . MacTech . 3 (1). Archivado del original el 29-06-2011 . Recuperado el 28-08-2008 .
  5. 1 2 Kidd, Eric. Entrenamiento de respuesta al terrorismo en Scheme . CUFP 2007. Archivado del original el 21-12-2010 . Recuperado el 26-08-2009 .
  6. 1 2 Cleis, Richard. Esquema en el espacio . CUFP 2006. Archivado del original el 27 de mayo de 2010. Recuperado el 26 de agosto de 2009 .
  7. 1 2 "Guía del lenguaje Wolfram: Programación funcional" . 2015. Consultado el 24 de agosto de 2015 .
  8. "Lenguaje de programación funcional vs. procedimental" . Departamento de Matemáticas Aplicadas . Universidad de Colorado. Archivado del original el 13 de noviembre de 2007. Consultado el 28 de agosto de 2006 .
  9. "Scripting basado en estados en Uncharted 2" (PDF) . Archivado del original (PDF) el 15/12/2012 . Consultado el 08/08/2011 .
  10. 1 2 "¿Quién usa Erlang para el desarrollo de productos?" . Preguntas frecuentes sobre Erlang . Consultado el 27 de abril de 2018 .
  11. 1 2 Armstrong, Joe (junio de 2007). "Una historia de Erlang". Actas de la tercera conferencia ACM SIGPLAN sobre la historia de los lenguajes de programación . Tercera conferencia ACM SIGPLAN sobre la historia de los lenguajes de programación. San Diego, California. doi : 10.1145/1238844.1238850 . ISBN 9781595937667.
  12. 1 2 Larson, Jim (marzo de 2009). "Erlang para programación concurrente" . Communications of the ACM . 52 (3): 48. doi : 10.1145/1467247.1467263 . S2CID 524392 . 
  13. "El lenguaje de programación Elixir" . Consultado el 14 de febrero de 2021 .
  14. 1 2 Minsky, Yaron; Weeks, Stephen (julio de 2008). "Caml Trading : experiencias con programación funcional en Wall Street" . Journal of Functional Programming . 18 (4): 553– 564. doi : 10.1017/S095679680800676X . S2CID 30955392 .  
  15. 1 2 Leroy, Xavier. Algunos usos de Caml en la industria (PDF) . CUFP 2007. Archivado del original (PDF) el 8 de octubre de 2011. Recuperado el 26 de agosto de 2009 .
  16. 1 2 "Haskell en la industria" . Haskell Wiki . Consultado el 26 de agosto de 2009. Haskell tiene una amplia gama de usos comerciales, desde la industria aeroespacial y de defensa hasta las finanzas, pasando por empresas emergentes web, empresas de diseño de hardware y fabricantes de cortadoras de césped.
  17. 1 2 3 Hudak, Paul ; Hughes, J.; Jones, SP; Wadler, P. (junio de 2007). Una historia de Haskell: ser perezoso con la clase . Tercera Conferencia ACM SIGPLAN sobre Historia de los Lenguajes de Programación. San Diego, California. doi : 10.1145/1238844.1238856 . Recuperado el 26 de septiembre de 2013 .
  18. 1 2 Mansell, Howard (2008). Finanzas cuantitativas en F# . CUFP 2008. Archivado del original el 8 de julio de 2015. Recuperado el 29 de agosto de 2009 .
  19. 1 2 Peake, Alex (2009). La primera aplicación sustancial de línea de negocio en F# . CUFP 2009. Archivado del original el 17 de octubre de 2009. Recuperado el 29 de agosto de 2009 .
  20. de Moura, Leonardo; Ullrich, Sebastian (julio de 2021). "El demostrador de teoremas y lenguaje de programación Lean 4". Lecture Notes in Artificial Intelligence . Conferencia sobre deducción automatizada. Vol. 12699. pp. 625–635 . doi : 10.1007/978-3-030-79876-5_37 . ISSN 1611-3349 .   
  21. Banz, Matt (27-06-2017). "Una introducción a la programación funcional en JavaScript" . Opensource.com . Recuperado el 09-01-2021 .
  22. "El programa de la conferencia useR! 2006 incluye ponencias sobre el uso comercial de R" . R-project.org. 8 de junio de 2006. Consultado el 20 de junio de 2011 .
  23. Chambers, John M. (1998). Programación con datos: Una guía del lenguaje S. Springer Verlag. págs. 67–70 . ISBN  978-0-387-98503-9.
  24. Novatchev, Dimitre. "El lenguaje de programación funcional XSLT: una demostración mediante ejemplos" . Consultado el 27 de mayo de 2006 .
  25. Mertz, David. "Paradigmas de programación XML (cuarta parte): Enfoque de programación funcional para el procesamiento de XML" . IBM developerWorks . Consultado el 27 de mayo de 2006 .
  26. Chamberlin, Donald D. ; Boyce, Raymond F. (1974). "SEQUEL: Un lenguaje de consulta estructurado en inglés". Actas del ACM SIGFIDET de 1974 : 249–264 .
  27. Programación funcional con C# - Simon Painter - NDC Oslo 2020 , 8 de agosto de 2021, archivado del original el 30 de octubre de 2021 , consultado el 23 de octubre de 2021
  28. 1 2 "Programación funcional - Lenguaje de programación Kotlin" . Kotlin . Consultado el 1 de mayo de 2019 .
  29. Dominus, Mark J. (2005). Higher-Order Perl . Morgan Kaufmann . ISBN 978-1-55860-701-9.
  30. ^ Holywell, Simón (2014). Programación funcional en PHP . php[arquitecto]. ISBN 9781940111056.
  31. The Cain Gang Ltd. "Metaclases de Python: ¿Quiénes? ¿Por qué? ¿Cuándo?" (PDF) . Archivado del original (PDF) el 30 de mayo de 2009. Consultado el 27 de junio de 2009 .
  32. "GopherCon 2020: Dylan Meeus - Programación funcional con Go" . YouTube . 22 de diciembre de 2020.
  33. "Características del lenguaje funcional: iteradores y cierres - El lenguaje de programación Rust" . doc.rust-lang.org . Consultado el 9 de enero de 2021 .
  34. Vanderbauwhede, Wim (18 de julio de 2020). "Código más limpio con programación funcional" . Archivado del original el 28 de julio de 2020. Recuperado el 6 de octubre de 2020 .
  35. "Effective Scala" . Scala Wiki . Archivado del original el 19 de junio de 2012. Consultado el 21 de febrero de 2012. Effective Scala.
  36. "Documentación para el paquete java.util.function desde Java 8 (también conocido como Java 1.8)" . Consultado el 16 de junio de 2021 .
  37. Turing, AM (1937). "Computabilidad y λ-definibilidad". The Journal of Symbolic Logic . 2 (4). Cambridge University Press: 153– 163. doi : 10.2307/2268280 . JSTOR 2268280. S2CID 2317046 .  
  38. Haskell Brooks Curry; Robert Feys (1958). Lógica combinatoria . North-Holland Publishing Company . Consultado el 10 de febrero de 2013 .
  39. Church, A. (1940). " Una formulación de la teoría simple de tipos". Journal of Symbolic Logic . 5 (2): 56– 68. doi : 10.2307/2266170 . JSTOR 2266170. S2CID 15889861 .  
  40. McCarthy, John (junio de 1978). "Historia de LISP". La primera conferencia ACM SIGPLAN sobre la historia de los lenguajes de programación - HOPL-1 (PDF) . Los Ángeles, CA. págs. 173–185 . doi : 10.1145/800025.808387 . {{cite book}}: CS1 mantenimiento: falta el editor de ubicación ( enlace )
  41. John McCarthy (1960). "Funciones recursivas de expresiones simbólicas y su cálculo por máquina, Parte I." (PDF) . Communications of the ACM . 3 (4): 184– 195. doi : 10.1145/367177.367199 . S2CID 1489409 . 
  42. Guy L. Steele; Richard P. Gabriel (febrero de 1996). «La evolución de Lisp». Historia de los lenguajes de programación - II (PDF) . págs. 233-330 . doi : 10.1145/234286.1057818 . ISBN  978-0-201-89502-5. S2CID 47047140 . 
  43. Las memorias de Herbert A. Simon (1991), Modelos de mi vida, págs. 189-190 ISBN 0-465-04640-1Afirma que él, Al Newell y Cliff Shaw son considerados comúnmente los padres del campo de la inteligencia artificial por haber escrito Logic Theorist , un programa que demostraba automáticamente teoremas de Principia Mathematica . Para lograrlo, tuvieron que inventar un lenguaje y un paradigma que, en retrospectiva, incorpora la programación funcional.
  44. Landin, Peter J. (1964). "La evaluación mecánica de expresiones" . The Computer Journal . 6 (4). British Computer Society : 308–320 . doi : 10.1093/comjnl/ 6.4.308 .
  45. Diehl, Stephan; Hartel, Pieter; Sestoft, Peter (2000). "Máquinas abstractas para la implementación de lenguajes de programación". Future Generation Computer Systems . Vol. 16. pp. 739–751 .  
  46. Landin, Peter J. (febrero de 1965a). "Correspondencia entre ALGOL 60 y la notación Lambda de Church: parte I" . Communications of the ACM . 8 (2). Association for Computing Machinery : 89–101 . doi : 10.1145/363744.363749 . S2CID 6505810 . 
  47. Landin, Peter J. (marzo de 1965b). "Una correspondencia entre ALGOL 60 y la notación Lambda de Church: parte II" . Communications of the ACM . 8 (3). Association for Computing Machinery : 158–165 . doi : 10.1145/363791.363804 . S2CID 15781851 . 
  48. Landin, Peter J. (marzo de 1966b). "Los próximos 700 lenguajes de programación" . Communications of the ACM . 9 (3). Association for Computing Machinery : 157–166 . doi : 10.1145/365230.365257 . S2CID 13409665 . 
  49. Backus, J. (1978). "¿Puede liberarse la programación del estilo von Neumann?: Un estilo funcional y su álgebra de programas" . Communications of the ACM . 21 (8): 613– 641. doi : 10.1145/359576.359579 .
  50. Backus, John (1978-08-01). "¿Puede liberarse la programación del estilo von Neumann? Un estilo funcional y su álgebra de programas" . Commun. ACM . 21 (8): 613– 641. doi : 10.1145/359576.359579 . ISSN 0001-0782 . 
  51. RM Burstall. Consideraciones de diseño para un lenguaje de programación funcional. Ponencia invitada, Actas de la Conferencia Infotech sobre el Estado del Arte "La Revolución del Software", Copenhague, 45–57 (1977)
  52. RM Burstall y J. Darlington. Un sistema de transformación para el desarrollo de programas recursivos. Journal of the Association for Computing Machinery 24(1):44–67 (1977)
  53. RM Burstall, DB MacQueen y DT Sannella. HOPE: un lenguaje aplicativo experimental. Actas de la Conferencia LISP de 1980, Stanford, 136–143 (1980).
  54. Zhenjiang Hu y John Hughes y Meng Wang (2015). "Cómo influyó la programación funcional". National Science Review . 2 : 349–370 . doi : 10.1093/NSR/NWV042 .
  55. "¡Haz que descubrir assign() sea más fácil!" . OpenSCAD . Archivado del original el 19/04/2023.
  56. Peter Bright (13 de marzo de 2018). "A los desarrolladores les encantan los lenguajes nuevos y de moda, pero ganan más con la programación funcional" . Ars Technica .
  57. John Leonard (24 de enero de 2017). "El ascenso sigiloso de la programación funcional" . Computing.
  58. Leo Cheung (9 de mayo de 2017). "¿Es mejor la programación funcional para tu startup?" . InfoWorld .
  59. Sean Tull - Categorías monoidales para el análisis formal de conceptos.
  60. Pountain, Dick. "La programación funcional alcanza la madurez" . Byte (agosto de 1994) . Archivado del original el 27 de agosto de 2006. Consultado el 31 de agosto de 2006 .
  61. 1 2 "ISO/IEC JTC 1/SC 22/WG5/N2137 – Fortran 2015 Committee Draft (J3/17-007r2)" (PDF) . Organización Internacional de Normalización. 6 de julio de 2017. págs. 336–338 . 
  62. "Informe revisado^6 sobre el esquema del lenguaje algorítmico" . R6rs.org . Consultado el 21 de marzo de 2013 .
  63. "Informe revisado^6 sobre el esquema del lenguaje algorítmico - Fundamentación" . R6rs.org . Consultado el 21 de marzo de 2013 .
  64. Clinger, William (1998). "Recursión de cola adecuada y eficiencia espacial". Actas de la conferencia ACM SIGPLAN 1998 sobre diseño e implementación de lenguajes de programación - PLDI '98 . págs. 174–185 . doi : 10.1145/277650.277719 . ISBN  0897919874. S2CID 16812984 . 
  65. Baker, Henry (1994). "CONS Should Not CONS Its Arguments, Part II: Cheney on the MTA" Archivado del original el 3 de marzo de 2006. Recuperado el 29 de abril de 2020 .
  66. Turner, DA (2004-07-28). "Programación funcional total" . Journal of Universal Computer Science . 10 (7): 751– 768. doi : 10.3217/jucs-010-07-0751 .
  67. La implementación de lenguajes de programación funcional . Simon Peyton Jones, publicado por Prentice Hall, 1987.
  68. 1 2 Launchbury, John (marzo de 1993). Una semántica natural para la evaluación perezosa . Simposio sobre principios de lenguajes de programación. Charleston, Carolina del Sur: ACM . págs. 144–154 . doi : 10.1145/158511.158618 . 
  69. Robert W. Harper (2009). Fundamentos prácticos de los lenguajes de programación (PDF) . Archivado del original (PDF) el 7 de abril de 2016.
  70. Huet, Gérard P. (1973). "La indecidibilidad de la unificación en la lógica de tercer orden". Information and Control . 22 (3): 257– 267. doi : 10.1016/s0019-9958(73)90301-x .
  71. ^ Huet, Gérard (septiembre de 1976). Resolución de ecuaciones en los idiomas de orden 1,2,... ω (Ph.D.) (en francés). Universidad de París VII.
  72. Huet, Gérard (2002). "Unificación de orden superior 30 años después" (PDF) . En Carreño, V.; Muñoz, C.; Tahar, S. (eds.). Actas de la XV Conferencia Internacional TPHOL . LNCS. Vol. 2410. Springer. pp. 3–12 .  
  73. Wells, JB (1993). "La tipabilidad y la verificación de tipos en el cálculo lambda de segundo orden son equivalentes e indecidibles". Informe técnico 93-011 : 176–185 . CiteSeerX 10.1.1.31.3590 . 
  74. Leroy, Xavier (17 de septiembre de 2018). "El compilador verificado Compcert" .
  75. Peyton Jones, Simon; Vytiniotis, Dimitrios; Weirich, Stephanie ; Geoffrey Washburn (abril de 2006). "Inferencia de tipos simple basada en unificación para GADT" . Icfp 2006 : 50–61 .
  76. "Manual de OCaml" . caml.inria.fr . Consultado el 8 de marzo de 2021 .
  77. "Tipos de datos algebraicos" . Documentación de Scala . Consultado el 8 de marzo de 2021 .
  78. Kennedy, Andrew; Russo, Claudio V. (octubre de 2005). Tipos de datos algebraicos generalizados y programación orientada a objetos (PDF) . OOPSLA. San Diego, California: ACM . doi : 10.1145/1094811.1094814 . ISBN 9781595930316Archivado del original el 29 de diciembre de 2006.
  79. Hughes, John. "Por qué importa la programación funcional" (PDF) . Universidad Tecnológica de Chalmers .
  80. Estructuras de datos puramente funcionales por Chris Okasaki , Cambridge University Press , 1998, ISBN 0-521-66350-4
  81. L'orange, Jean Niklas. "polymatheia - Understanding Clojure's Persistent Vector, pt. 1" . Polymatheia . Consultado el 13 de noviembre de 2018 .
  82. Michael Barr, Charles Well - Teoría de categorías para la informática.
  83. Newbern, J. "Todo sobre las mónadas: una guía completa sobre la teoría y la práctica de la programación monádica en Haskell" . Consultado el 14 de febrero de 2008 .
  84. "Trece maneras de mirar una tortuga" . fF# para divertirse y obtener ganancias . Consultado el 13 de noviembre de 2018 .
  85. "Valores y cambio: el enfoque de Clojure hacia la identidad y el estado" . Clojure.org . Consultado el 22 de junio de 2026 .
  86. Hartmanis, Juris; Hemachandra, Lane (1986). «Clases de complejidad sin máquinas: Sobre lenguajes completos para UP». Autómatas, lenguajes y programación . Notas de clase en ciencias de la computación. Vol. 226. Berlín, Heidelberg: Springer Berlin Heidelberg. pp. 123–135 . doi : 10.1007/3-540-16761-7_62 . ISBN   978-3-540-16761-7. Consultado el 12 de diciembre de 2024 .
  87. Paulson, Larry C. (28 de junio de 1996). ML para el programador profesional . Cambridge University Press. ISBN 978-0-521-56543-1Consultado el 10 de febrero de 2013 .
  88. Spiewak, Daniel (26 de agosto de 2008). "Implementación de vectores persistentes en Scala" . Code Commit . Archivado del original el 23 de septiembre de 2015. Recuperado el 17 de abril de 2012 .
  89. "¿Qué programas son más rápidos? | Juego de evaluación comparativa de lenguajes informáticos" . benchmarksgame.alioth.debian.org. Archivado del original el 20 de mayo de 2013. Consultado el 20 de junio de 2011 .
  90. Igor Pechtchanski; Vivek Sarkar (2005). "Especificación de inmutabilidad y sus aplicaciones". Concurrency and Computation: Practice and Experience . 17 ( 5–6 ): 639–662 . doi : 10.1002/cpe.853 . S2CID 34527406 . 
  91. "Una mirada en profundidad a las colecciones de Clojure" . InfoQ . Consultado el 29 de abril de 2024 .
  92. "Referencias y préstamos - El lenguaje de programación Rust" . doc.rust-lang.org . Consultado el 29 de abril de 2024 .
  93. "Validación de referencias con tiempos de vida - El lenguaje de programación Rust" . doc.rust-lang.org . Consultado el 29 de abril de 2024 .
  94. "Colecciones concurrentes (Tutoriales de Java™ > Clases esenciales de Java > Concurrencia)" . docs.oracle.com . Consultado el 29 de abril de 2024 .
  95. "Comprender el modelo de actor para construir sistemas distribuidos sin bloqueo y de alto rendimiento - Scaleyourapp" . scaleyourapp.com . 28 de enero de 2023. Consultado el 29 de abril de 2024 .
  96. Cesarini, Francesco; Thompson, Simon (2009). Programación en Erlang: un enfoque concurrente para el desarrollo de software (1.ª ed.). O'Reilly Media, Inc. (publicado el 11 de junio de 2009). pág. 6. ISBN   978-0-596-55585-6.
  97. "Capítulo 25. Perfilado y optimización" . Book.realworldhaskell.org . Consultado el 20 de junio de 2011 .
  98. Nethercote, Nicholas; Mycroft, Alan (16 de junio de 2002). "El comportamiento de la caché de programas funcionales grandes y perezosos en hardware estándar" . ACM SIGPLAN Notices . 38 (2 suplemento): 44–55 . doi : 10.1145/773039.773044 . ISSN 0362-1340 . 
  99. ^ Berthe, Samuel (29 de abril de 2024), samber/lo , consultado el 29 de abril de 2024
  100. "Go Wiki: Optimizaciones del compilador y del tiempo de ejecución - El lenguaje de programación Go" . go.dev . Consultado el 29 de abril de 2024 .
  101. "Comparación de rendimiento: bucles frente a iteradores - El lenguaje de programación Rust" . doc.rust-lang.org . Consultado el 29 de abril de 2024 .
  102. Hartel, Pieter; Henk Muller; Hugh Glaser (marzo de 2004). "La experiencia de C funcional" (PDF) . Journal of Functional Programming . 14 (2): 129– 135. doi : 10.1017/S0956796803004817 . S2CID 32346900. Archivado del original (PDF) el 19 de julio de 2011. Recuperado el 28 de mayo de 2006 . ; David Mertz. "Programación funcional en Python, Parte 3" . IBM developerWorks . Archivado del original el 16 de octubre de 2007. Consultado el 17 de septiembre de 2006 .( Parte 1 , Parte 2 )
  103. "Funciones — Lenguaje de programación D 2.0" . Digital Mars. 30 de diciembre de 2012. 
  104. "Preguntas frecuentes no oficiales de Lua (uFAQ)" .
  105. "Funciones de primera clase en Go - El lenguaje de programación Go" . golang.org . Consultado el 4 de enero de 2021 .
  106. Eich, Brendan (3 de abril de 2008). "Popularidad" .
  107. van Rossum, Guido (2009-04-21). "Orígenes de las características "funcionales" de Python" . Recuperado el 27 de septiembre de 2012 .
  108. "functools — Funciones y operaciones de orden superior en objetos invocables" . Python Software Foundation. 31 de julio de 2011. Consultado el 31 de julio de 2011 .
  109. Skarsaune, Martin (2008). El proyecto SICS Java Port: traducción automática de un gran sistema orientado a objetos de Smalltalk a Java .
  110. Gosling, James. "Closures" . James Gosling: on the Java Road . Oracle. Archivado del original el 14 de abril de 2013. Consultado el 11 de mayo de 2013 .
  111. Williams, Michael (8 de abril de 2013). "Java SE 8 Lambda Quick Start" .
  112. Bloch, Joshua (2008). "Punto 15: Minimizar la mutabilidad". Effective Java (Segunda edición). Addison-Wesley. ISBN  978-0321356680.
  113. "Object.freeze() - JavaScript | MDN" . developer.mozilla.org . Consultado el 4 de enero de 2021. El método Object.freeze() congela un objeto. Un objeto congelado ya no se puede modificar; congelar un objeto impide que se le añadan nuevas propiedades, que se eliminen las existentes, que se modifique la enumerabilidad, la configurabilidad o la posibilidad de escritura de las propiedades existentes, y que se modifiquen los valores de las propiedades existentes. Además, congelar un objeto también impide que se modifique su prototipo. freeze() devuelve el mismo objeto que se le pasó como argumento.
  114. Daniel Friedman; William Byrd; Oleg Kiselyov; Jason Hemann (2018). El estratega razonado, segunda edición . The MIT Press.
  115. A. Casas, D. Cabeza, MV Hermenegildo. Un enfoque sintáctico para combinar la notación funcional, la evaluación perezosa y el orden superior en sistemas de programación lógica. VIII Simposio Internacional sobre Programación Funcional y Lógica (FLOPS'06), páginas 142-162, abril de 2006.
  116. "Cómo hago mis tareas informáticas" . stallman.org . Consultado el 29 de abril de 2024 .
  117. Wakeling, David (2007). "Programación funcional en hojas de cálculo" (PDF) . Journal of Functional Programming . 17 (1): 131– 143. doi : 10.1017/S0956796806006186 . ISSN 0956-7968 . S2CID 29429059 .  
  118. Peyton Jones, Simon ; Burnett, Margaret ; Blackwell, Alan (marzo de 2003). "Mejorando el lenguaje funcional más popular del mundo: funciones definidas por el usuario en Excel" . Archivado del original el 16 de octubre de 2005.
  119. Rodger, Richard (11 de diciembre de 2017). El Tao de los Microservicios . Manning. ISBN 9781638351733.
  120. Piro, Christopher (2009). Programación funcional en Facebook . CUFP 2009. Archivado del original el 17 de octubre de 2009. Recuperado el 29 de agosto de 2009 .
  121. "Sim-Diasca: un motor de simulación concurrente de eventos discretos a gran escala en Erlang" . Noviembre de 2011. Archivado del original el 17 de septiembre de 2013. Consultado el 8 de noviembre de 2011 .
  122. 1 millón es tan de 2011 Archivado el 19/02/2014 en Wayback Machine // Blog de WhatsApp, 06/01/2012: "la última pieza importante de nuestra infraestructura es Erlang"
  123. Momtahan, Lee (2009). Scala en EDF Trading: Implementación de un lenguaje específico de dominio para la valoración de derivados con Scala . CUFP 2009. Archivado del original el 17 de octubre de 2009. Consultado el 29 de agosto de 2009 .
  124. Graham, Paul (2003). "Beating the Averages" . Recuperado el 29 de agosto de 2009 .
  125. Sims, Steve (2006). Building a Startup with Standard ML (PDF) . CUFP 2006. Recuperado el 29 de agosto de 2009 .
  126. Laurikari, Ville (2007). Programación funcional en seguridad de las comunicaciones . CUFP 2007. Archivado del original el 21-12-2010 . Recuperado el 29-08-2009 .
  127. Lorimer, RJ (19 de enero de 2009). "Anunciada la aplicación de Clojure para producción en vivo" . InfoQ .
  128. Bugnion, Pascal (2016). Scala para la ciencia de datos (1.ª ed.). Packt . ISBN  9781785281372.
  129. "Por qué a los desarrolladores les gusta ClojureScript" . StackShare . Consultado el 29 de abril de 2024 .
  130. Herrick, Justin (29/04/2024), jah2488/elm-companies , consultado el 29/04/2024
  131. "Por qué a los desarrolladores les gusta PureScript" . StackShare . Consultado el 29 de abril de 2024 .
  132. Equipo Editorial (8 de enero de 2019). "ALLEGRO: todo lo que necesitas saber sobre el mejor mercado online polaco" . Noticias de comercio electrónico en Alemania . Consultado el 29 de abril de 2024 .
  133. "Sitios web que utilizan Phoenix Framework - Wappalyzer" . www.wappalyzer.com . Consultado el 29 de abril de 2024 .
  134. "Programación funcional: 2019-2020" . Departamento de Ciencias de la Computación de la Universidad de Oxford . Consultado el 28 de abril de 2020 .
  135. "Programación I (Haskell)" . Departamento de Informática del Imperial College de Londres . Consultado el 28 de abril de 2020 .
  136. 1 2 "Licenciatura en Ciencias de la Computación - Módulos" . Consultado el 28 de abril de 2020 .
  137. 1 2 Abelson, Hal ; Sussman, Gerald Jay (1985). "Prefacio a la segunda edición" . Estructura e interpretación de programas informáticos (2.ª ed.). MIT Press. Bibcode : 1985sicp.book.....A . 
  138. John DeNero (otoño de 2019). "Informática 61A, Berkeley" . Departamento de Ingeniería Eléctrica e Informática, Berkeley . Consultado el 14 de agosto de 2020 .
  139. Emmanuel Schanzer de Bootstrap fue entrevistado en el programa de televisión Triangulation de la cadena TWiT.tv.
  140. "¿Por qué Scheme para la programación introductoria?" . home.adelphi.edu . Consultado el 29 de abril de 2024 .
  141. Personal de IMACS (3 de junio de 2011). "¿Qué es Scheme y por qué es beneficioso para los estudiantes?" . IMACS – Formando mejores pensadores para la vida . Consultado el 29 de abril de 2024 .

Lecturas adicionales

  • Abelson, Hal ; Sussman, Gerald Jay (1985). Estructura e interpretación de programas informáticos . MIT Press. Bibcode : 1985sicp.book.....A . ISBN 978-0-262-51036-3.
  • Cousineau, Guy y Michel Mauny. El enfoque funcional de la programación . Cambridge, Reino Unido: Cambridge University Press , 1998.
  • Curry, Haskell Brooks y Feys, Robert y Craig, William. Lógica combinatoria . Volumen I. North-Holland Publishing Company, Ámsterdam, 1958.
  • Curry, Haskell B .; Hindley, J. Roger ; Seldin, Jonathan P. (1972). Lógica combinatoria . Vol.  II. Ámsterdam: North Holland. ISBN 978-0-7204-2208-5.
  • Dominus, Mark Jason. Perl de orden superior . Morgan Kaufmann . 2005.
  • Felleisen, Matthias; Findler, Robert; Flatt, Matthew; Krishnamurthi, Shriram (2018). Cómo diseñar programas . MIT Press.
  • Graham, Paul. ANSI Common LISP . Englewood Cliffs, Nueva Jersey: Prentice Hall , 1996.
  • MacLennan, Bruce J. Programación funcional: práctica y teoría . Addison-Wesley, 1990.
  • Michaelson, Greg (10 de abril de 2013). Introducción a la programación funcional mediante el cálculo lambda . Courier Corporation. ISBN 978-0-486-28029-5.
  • O'Sullivan, Brian; Stewart, Don; Goerzen, John (2008). Haskell en el mundo real . O'Reilly.
  • Pratt, Terrence W. y Marvin Victor Zelkowitz . Lenguajes de programación: diseño e implementación . 3.ª ed. Englewood Cliffs, Nueva Jersey: Prentice Hall , 1996.
  • Salus, Peter H. Lenguajes de programación funcional y lógica . Vol. 4 del Manual de lenguajes de programación. Indianápolis, Indiana: Macmillan Technical Publishing , 1998.
  • Thompson, Simon. Haskell: El arte de la programación funcional . Harlow, Inglaterra: Addison-Wesley Longman Limited , 1996.
  • Ford, Neal. "Pensamiento funcional" . Recuperado el 10 de noviembre de 2021 .
  • Akhmechet, Slava (19 de junio de 2006). "defmacro – Programación funcional para todos nosotros" . Recuperado el 24 de febrero de 2013 .Una introducción
  • Programación funcional en Python (por David Mertz): parte 1 , parte 2 , parte 3