[function] ¿Cuál es la diferencia entre un 'cierre' y un 'lambda'?



4 Answers

Cuando la mayoría de las personas piensa en funciones , piensan en funciones nombradas :

function foo() { return "This string is returned from the 'foo' function"; }

Estos son llamados por su nombre, por supuesto:

foo(); //returns the string above

Con las expresiones lambda , puede tener funciones anónimas :

 @foo = lambda() {return "This is returned from a function without a name";}

Con el ejemplo anterior, puede llamar a la lambda a través de la variable a la que se le asignó:

foo();

Sin embargo, son más útiles que la asignación de funciones anónimas a las variables, ya que las transfieren a funciones de orden superior o desde ellas, es decir, funciones que aceptan / devuelven otras funciones. En muchos de estos casos, nombrar una función es innecesario:

function filter(list, predicate) 
 { @filteredList = [];
   for-each (@x in list) if (predicate(x)) filteredList.add(x);
   return filteredList;
 }

//filter for even numbers
filter([0,1,2,3,4,5,6], lambda(x) {return (x mod 2 == 0)}); 

Un cierre puede ser una función nombrada o anónima, pero se conoce como tal cuando "cierra" variables en el ámbito donde se define la función, es decir, el cierre todavía se referirá al entorno con cualquier variable externa que se use en el cierre en sí mismo. Aquí hay un cierre con nombre:

@x = 0;

function incrementX() { x = x + 1;}

incrementX(); // x now equals 1

Eso no parece mucho, pero ¿y si todo esto estuviera en otra función y pasaras incrementX a una función externa?

function foo()
 { @x = 0;

   function incrementX() 
    { x = x + 1;
      return x;
    }

   return incrementX;
 }

@y = foo(); // y = closure of incrementX over foo.x
y(); //returns 1 (y.x == 0 + 1)
y(); //returns 2 (y.x == 1 + 1)

Así es como obtienes objetos con estado en la programación funcional. Dado que no es necesario nombrar "incrementX", puede usar un lambda en este caso:

function foo()
 { @x = 0;

   return lambda() 
           { x = x + 1;
             return x;
           };
 }
Question

¿Alguien podría explicar? Entiendo los conceptos básicos detrás de ellos, pero a menudo los veo intercambiados y me confundo.

Y ahora que estamos aquí, ¿cómo difieren de una función normal?




Esta pregunta es antigua y obtuvo muchas respuestas. Ahora con Java 8 y Official Lambda que son proyectos de cierre no oficiales, se reaviva la pregunta.

La respuesta en el contexto de Java (a través de Lambdas y cierres: ¿cuál es la diferencia? ):

"Un cierre es una expresión lambda emparejada con un entorno que vincula cada una de sus variables libres a un valor. En Java, las expresiones lambda se implementarán mediante cierres, por lo que los dos términos se utilizarán indistintamente en la comunidad".




Una lambda es solo una función anónima, una función definida sin nombre. Un cierre es cualquier función que se cierra sobre el entorno en el que se definió. Esto significa que puede acceder a variables que no están en su lista de parámetros.




Desde la vista de los lenguajes de programación, son completamente dos cosas diferentes.

Básicamente para un lenguaje completo de Turing solo necesitamos elementos muy limitados, por ejemplo, abstracción, aplicación y reducción. La abstracción y la aplicación proporcionan la manera en que puedes construir la expresión de lamdba, y la reducción determina el significado de la expresión lambda.

Lambda proporciona una forma de abstraer el proceso de cálculo. por ejemplo, para calcular la suma de dos números, se puede abstraer un proceso que toma dos parámetros x, y y devuelve x + y. En el esquema, puede escribirlo como

(lambda (x y) (+ x y))

Puede cambiar el nombre de los parámetros, pero la tarea que completa no cambia. En casi todos los lenguajes de programación, puede darle un nombre a la expresión lambda, que se denominan funciones. Pero no hay mucha diferencia, se pueden considerar conceptualmente como solo azúcar sintáctico.

OK, ahora imagina cómo se puede implementar esto. Siempre que apliquemos la expresión lambda a algunas expresiones, por ejemplo

((lambda (x y) (+ x y)) 2 3)

Simplemente podemos sustituir los parámetros con la expresión que se evaluará. Este modelo ya es muy poderoso. Pero este modelo no nos permite cambiar los valores de los símbolos, por ejemplo, no podemos imitar el cambio de estado. Por lo tanto, necesitamos un modelo más complejo. Para abreviar, cada vez que queremos calcular el significado de la expresión lambda, colocamos el par de símbolos y el valor correspondiente en un entorno (o tabla). Luego, el resto (+ xy) se evalúa buscando los símbolos correspondientes en la tabla. Ahora, si proporcionamos algunas primitivas para operar en el entorno directamente, ¡podemos modelar los cambios de estado!

Con este fondo, verifica esta función:

(lambda (x y) (+ x y z))

Sabemos que cuando evaluamos la expresión lambda, xy estará vinculado en una nueva tabla. Pero, ¿cómo y dónde podemos buscar z? En realidad, z se llama una variable libre. Debe haber un entorno externo que contenga z. De lo contrario, el significado de la expresión no puede determinarse solo vinculando xey. Para aclarar esto, puede escribir algo de la siguiente manera en el esquema:

((lambda (z) (lambda (x y) (+ x y z))) 1)

Entonces z estaría limitado a 1 en una tabla externa. Todavía obtenemos una función que acepta dos parámetros, pero el significado real también depende del entorno exterior. En otras palabras, el entorno externo se cierra en las variables libres. Con la ayuda de set !, podemos hacer que la función sea estable, es decir, no es una función en el sentido de las matemáticas. Lo que devuelve no solo depende de la entrada, sino también de z.

Esto es algo que ya sabes muy bien, un método de objetos casi siempre depende del estado de los objetos. Es por eso que algunas personas dicen que "los cierres son objetos de los pobres". Pero también podríamos considerar los objetos como cierres de pobres porque realmente nos gustan las funciones de primera clase.

Yo uso el esquema para ilustrar las ideas debido a que el esquema es uno de los primeros lenguajes que tiene cierres reales. Todos los materiales aquí están mucho mejor presentados en el capítulo 3 del SICP.

En resumen, Lambda y cierre son conceptos realmente diferentes. Una lambda es una función. Un cierre es un par de lambda y el entorno correspondiente que cierra la lambda.




No todos los cierres son lambdas y no todas las lambdas son cierres. Ambas son funciones, pero no necesariamente de la manera que estamos acostumbrados a saber.

Una lambda es esencialmente una función que se define en línea en lugar del método estándar para declarar funciones. Las lambdas con frecuencia se pueden pasar como objetos.

Un cierre es una función que encierra su estado circundante al hacer referencia a campos externos a su cuerpo. El estado cerrado permanece en todas las invocaciones del cierre.

En un lenguaje orientado a objetos, los cierres se proporcionan normalmente a través de objetos. Sin embargo, algunos lenguajes OO (por ejemplo, C #) implementan una funcionalidad especial que se acerca más a la definición de cierres proporcionados por lenguajes puramente funcionales (como lisp) que no tienen objetos para encerrar el estado.

Lo interesante es que la introducción de Lambdas y Closures en C # acerca la programación funcional al uso general.




Related