programming languages programming-languages functional-programming lisp

programming languages - languages - Los efectos secundarios en los cierres, ¿siguen siendo puramente funcionales?



programming languages 2018 (3)

Tienes razón, usar cierres para manipular el estado no es puramente funcional. Lisp te permite programar en un estilo funcional, pero no te obliga a hacerlo. En realidad, prefiero este enfoque porque me permite encontrar un equilibrio pragmático entre lo puramente funcional y la conveniencia de modificar el estado.

Lo que podría intentar es escribir algo que parezca funcional desde el exterior pero que mantenga un estado interno mutable para mayor eficiencia. Un gran ejemplo de esto es la memorización en la que mantiene un registro de todas las invocaciones anteriores para acelerar funciones como fibonacci, pero como la función siempre devuelve el mismo resultado para la misma entrada y no modifica ningún estado externo, se puede considerar ser funcional desde el exterior.

Siendo relativamente nuevo en la programación funcional, gasto mucha energía preguntándome "¿es esta la manera funcional de hacer las cosas?" Obviamente, la recursión frente a la iteración es bastante directa y es obvio que la recursividad es la forma funcional de hacer las cosas. Pero toma cierres, por ejemplo. Aprendí acerca de cierres usando Lisp y entiendo que los cierres son una combinación de una función y un entorno (suena muy parecido al estado y al comportamiento). Por ejemplo:

(let ((x 1)) (defun doubleX() (setf x (* x 2))))

Aquí tenemos una función doubleX que se ha definido dentro del entorno de la variable x. Podríamos pasar esta función a otras funciones y luego invocarla y todavía será posible hacer referencia a la variable x. La función puede seguir haciendo referencia a esa variable, incluso si se invoca fuera del entorno donde se ha definido la variable. Muchos de los ejemplos que he visto de cierres se ven así. Donde setf se usa para cambiar el valor de la variable léxica. Esto me confunde porque:

1.) Pensé que setf era malvado. Principalmente porque causa efectos secundarios y aparentemente también son malvados.

2.) ¿Es esto realmente "funcional"? Parece solo una forma de mantener el estado global y pensé que los lenguajes funcionales eran apátridas.

Tal vez simplemente no entiendo los cierres. ¿Alguien me puede ayudar?


Common Lisp y Scheme no son puramente funcionales. Clojure es principalmente funcional, pero aún no puramente. Haskell es el único idioma que sé que es puramente funcional, ni siquiera puedo mencionar el nombre de otro.

La verdad es que trabajar en un entorno puramente funcional es muy difícil (ve, aprende Haskell y trata de programar algo sobre él). Entonces, todos estos lenguajes de programación funcionales realmente lo que hacen es permitir la programación funcional, pero no hacerla cumplir. La programación funcional es muy poderosa, así que úsala siempre que puedas y cuando no puedas.

Algo importante que debe saberse con la edad que se avecina es que todo lo funcional es paralelizable, por lo que tiene sentido evitar tener efectos secundarios o tener un subconjunto lo más pequeño posible de su programa como sea posible.


Los cierres son objetos de un hombre pobre (y viceversa), ver

Cuándo usar el cierre?

y mi respuesta allí. Entonces, si tiene la intención de utilizar efectos secundarios para administrar el estado en su aplicación no OO, los cierres sobre el estado mutable son de hecho una manera fácil de hacer esto. Las alternativas inmutables son "menos malvadas", pero el 99,9% de los idiomas ofrecen un estado variable y no todos pueden estar equivocados. :) El estado mutable es valioso cuando se usa de forma juiciosa, pero puede ser especialmente propenso a errores cuando se usa con cierres y captura, como se ve aquí.

En lambdas, captura y mutabilidad

En cualquier caso, creo que la razón por la que ve "tantos ejemplos como este" es que una de las formas más comunes de explicar el comportamiento de los cierres es mostrar un pequeño ejemplo como este en el que un cierre captura un mutable y se convierte en un mini -stateful-object que encapsula un estado mutable. Es un gran ejemplo para ayudarlo a asegurarse de que comprenda las implicaciones del constructo para toda la vida y los efectos colaterales, pero no es un respaldo ir y utilizar esta construcción por todos lados.

La mayoría de las veces, con cierres, cierra los valores o el estado inmutable y "no se da cuenta" de que lo está haciendo.