Muchos lenguajes de programación modernos admiten algún concepto de cierre , es decir, un fragmento de código (un bloque o una función) que
- Puede tratarse como un valor y, por lo tanto, almacenarse en una variable, transmitirse a diferentes partes del código, definirse en una parte de un programa e invocarse en una parte totalmente diferente del mismo programa.
- Puede capturar variables del contexto en el que se define y acceder a ellas cuando se invoca posteriormente (posiblemente en un contexto totalmente diferente).
Aquí hay un ejemplo de un cierre escrito en Scala:
def filterList(xs: List[Int], lowerBound: Int): List[Int] =
xs.filter(x => x >= lowerBound)
El literal de la función x => x >= lowerBound
contiene la variable libre lowerBound
, que está cerrada (vinculada) por el argumento de la función filterList
que tiene el mismo nombre. El cierre se pasa al método de la biblioteca filter
, que puede invocarlo repetidamente como una función normal.
He estado leyendo muchas preguntas y respuestas en este sitio y, por lo que entiendo, el término cierre a menudo se asocia automáticamente con la programación funcional y el estilo de programación funcional.
La definición de programación de funciones en wikipedia dice:
En informática, la programación funcional es un paradigma de programación que trata la computación como la evaluación de funciones matemáticas y evita el estado y los datos mutables. Enfatiza la aplicación de funciones, en contraste con el estilo de programación imperativo, que enfatiza los cambios de estado.
y más adelante
[...] en el código funcional, el valor de salida de una función depende solo de los argumentos que se ingresan a la función [...]. Eliminar los efectos secundarios puede hacer que sea mucho más fácil comprender y predecir el comportamiento de un programa, que es una de las motivaciones clave para el desarrollo de la programación funcional.
Por otro lado, muchas construcciones de cierre proporcionadas por lenguajes de programación permiten un cierre para capturar variables no locales y cambiarlas cuando se invoca el cierre, produciendo así un efecto secundario en el entorno en el que se definieron.
En este caso, los cierres implementan la primera idea de programación funcional (las funciones son entidades de primera clase que se pueden mover como otros valores) pero descuidan la segunda idea (evitando los efectos secundarios).
¿Este uso de cierres con efectos secundarios se considera un estilo funcional o los cierres se consideran una construcción más general que puede usarse tanto para un estilo de programación funcional como no funcional? ¿Hay alguna literatura sobre este tema?
NOTA IMPORTANTE
No estoy cuestionando la utilidad de los efectos secundarios o de tener cierres con efectos secundarios. Además, no estoy interesado en una discusión sobre las ventajas / desventajas de los cierres con o sin efectos secundarios.
Solo me interesa saber si el uso de tales cierres todavía se considera estilo funcional por el proponente de la programación funcional o si, por el contrario, se desaconseja su uso cuando se usa un estilo funcional.
fuente
Respuestas:
No; La definición de paradigma funcional es sobre la falta de estado y la falta implícita de efectos secundarios. No se trata de funciones de alto orden, cierres, manipulación de listas compatibles con el lenguaje u otras características del lenguaje ...
El nombre de la programación funcional proviene de la noción matemática de funciones : las llamadas repetidas en la misma entrada siempre dan la misma salida : función nipipotente. Esto solo se puede lograr si los datos son inmutables . Para facilitar el desarrollo, las funciones se volvieron mutables (las funciones cambian, los datos aún son inmutables) y, por lo tanto, la noción de funciones de orden superior (funciones en matemáticas, como derivadas, por ejemplo), una función que toma como entrada otra función. Para la posibilidad de llevar a cabo funciones y pasarlas como argumentos, se adoptaron funciones de primera clase ; Después de esto, para mejorar aún más la productividad, aparecieron cierres .
Esta es, por supuesto, una vista muy simplificada.
fuente
map
, por ejemplo, qué toma una función, la aplica a una lista y devuelve una lista de los resultados.map
no modifica ninguno de sus argumentos, no cambia el comportamiento de la función que toma como argumento, pero definitivamente es una función de orden superior: si la aplica parcialmente, solo con el parámetro de función, ha construido un nueva función que opera en una lista, pero aún no ha sucedido ninguna mutación.No. "Estilo funcional" implica una programación libre de efectos secundarios.
Para ver por qué, eche un vistazo a la entrada del blog de Eric Lippert sobre el
ForEach<T>
método de extensión y por qué Microsoft no incluyó un método de secuencia como este en Linq :fuente
ParallelQuery<T>.ForAll(...)
. La implementación de este tipoIEnumerable<T>.ForEach(...)
es extremadamente útil para depurar lasForAll
declaraciones (reemplaceForAll
conForEach
y elimine elAsParallel()
y puede hacerlo / depurarlo mucho más fácilmente)La programación funcional lleva las funciones de primera clase al siguiente nivel conceptual con seguridad, pero declarar funciones anónimas o pasar funciones a otras funciones no es necesariamente una cosa de programación funcional. En C, todo era un número entero. Un número, un puntero a datos, un puntero a una función ... todo solo int. Puede pasar punteros de función a otras funciones, hacer listas de punteros de función ... Demonios, si trabaja en lenguaje ensamblador, las funciones son realmente solo direcciones en la memoria donde se almacenan bloques de instrucciones de máquina. Darle un nombre a una función es una sobrecarga adicional para las personas que necesitan un compilador para escribir código. Entonces las funciones eran "de primera clase" en ese sentido en un lenguaje completamente no funcional.
Si lo único que haces es calcular fórmulas matemáticas en un REPL, entonces puedes ser funcionalmente puro con tu lenguaje. Pero la mayoría de la programación empresarial tiene efectos secundarios. Perder dinero mientras se espera que se complete un programa de larga duración es un efecto secundario. Tomar cualquier acción externa: escribir en un archivo, actualizar una base de datos, registrar eventos en orden, etc. requiere un cambio de estado. Podríamos debatir si el estado realmente ha cambiado si encapsula estas acciones en envoltorios inmutables que eliminan los efectos secundarios para que su código no tenga que preocuparse por ellos. Pero es como discutir si un árbol hace ruido si cae en el bosque sin nadie allí para escucharlo. El hecho es que el árbol comenzó en posición vertical y terminó en el suelo. El estado cambia cuando se hacen las cosas, aunque solo sea para informar que las cosas se hicieron.
Por lo tanto, nos queda una escala de pureza funcional, no en blanco y negro, sino en tonos de gris. Y en esa escala, cuantos menos efectos secundarios, menos mutabilidad, mejor (más funcional).
Si necesita un efecto secundario o un estado mutable en su código funcional, intente encapsularlo del resto de su programa lo mejor que pueda. Usar un cierre (o cualquier otra cosa) para inyectar efectos secundarios o estado mutable en funciones que de otra forma serían puras es la antítesis de la programación funcional. La única excepción podría ser si el cierre fuera la forma más efectiva de encapsular los efectos secundarios del código al que se pasa. Todavía no es "programación funcional", pero podría ser el armario que puede obtener en ciertas situaciones.
fuente