¿Cuál es la diferencia entre un 'cierre' y una 'lambda'?

811

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

Y ahora que estamos aquí, ¿en qué se diferencian de una función normal?

esquiador
fuente
85
Las lambdas son una construcción de lenguaje (funciones anónimas), los cierres son una técnica de implementación para implementar funciones de primera clase (sean anónimas o no). Desafortunadamente, esto a menudo es confundido por muchas personas.
Andreas Rossberg
Para los cierres de PHP, consulte php.net/manual/en/class.closure.php . No es lo que esperaría un programador de JavaScript.
PaulH
La respuesta de SasQ es excelente. En mi humilde opinión, esta pregunta sería más útil para los usuarios de SO si guiara a los espectadores a esa respuesta.
AmigoNico

Respuestas:

704

Una lambda es solo una función anónima, una función definida sin nombre. En algunos idiomas, como Scheme, son equivalentes a funciones con nombre. De hecho, la definición de la función se reescribe como un enlace interno de una lambda a una variable. En otros lenguajes, como Python, hay algunas distinciones (bastante innecesarias) entre ellos, pero de lo contrario se comportan de la misma manera.

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. Ejemplos:

def func(): return h
def anotherfunc(h):
   return func()

Esto provocará un error, porque funcno se cierra sobre el entorno en anotherfunc- hestá indefinido. funcsolo cierra sobre el entorno global. Esto funcionará:

def anotherfunc(h):
    def func(): return h
    return func()

Porque aquí, funcse define en anotherfunc, y en Python 2.3 y superior (o un número como este) cuando casi se cierran correctamente (la mutación todavía no funciona), esto significa que se cierra sobre anotherfunc el entorno y puede acceder a variables dentro de eso. En Python 3.1+, la mutación también funciona cuando se usa la nonlocalpalabra clave .

Otro punto importante: funccontinuará cerrándose sobre anotherfuncel entorno incluso cuando ya no se esté evaluando anotherfunc. Este código también funcionará:

def anotherfunc(h):
    def func(): return h
    return func

print anotherfunc(10)()

Esto imprimirá 10.

Esto, como notará, no tiene nada que ver con lambda s: son dos conceptos diferentes (aunque relacionados).

Claudiu
fuente
1
Claudiu, para mi incierto conocimiento, Python nunca ha tenido los cierres correctos. ¿Solucionaron el problema de mutabilidad mientras yo no estaba mirando? Muy posible ...
Simon
Simon: tienes razón, todavía no son del todo correctos. Creo que Python 3.0 agregará un truco para solucionar esto. (algo así como un identificador 'no local'). Cambiaré mi ansewr para reflejar eso.
Claudiu
2
@AlexanderOrlov: Ambos son lambdas y cierres. Java tuvo cierres antes a través de clases internas anónimas. Ahora esa funcionalidad se ha hecho sintácticamente más fácil a través de expresiones lambda. Entonces, probablemente el aspecto más relevante de la nueva característica es que ahora hay lambdas. No es incorrecto llamarlos lambdas, de hecho son lambdas. No sé por qué los autores de Java 8 pueden elegir no resaltar el hecho de que son cierres.
Claudiu
2
@AlexanderOrlov porque las lambdas de Java 8 no son cierres verdaderos, son simulaciones de cierres. Son más similares a los cierres de Python 2.3 (sin mutabilidad, de ahí el requisito de que las variables a las que se hace referencia sean 'efectivamente finales'), y se compilan internamente para funciones que no son de cierre que toman todas las variables a las que se hace referencia en el alcance adjunto como parámetros ocultos.
Recogida de Logan
77
@Claudiu Creo que la referencia a una implementación de lenguaje particular (Python) puede complicar demasiado la respuesta. La pregunta es completamente independiente del idioma (y no tiene etiquetas específicas del idioma).
Mateo
319

Hay mucha confusión sobre lambdas y cierres, incluso en las respuestas a esta pregunta de StackOverflow aquí. En lugar de preguntar a los programadores aleatorios que aprendieron acerca de los cierres de la práctica con ciertos lenguajes de programación u otros programadores despistados, emprendan un viaje hacia la fuente (donde todo comenzó). Y dado que las lambdas y los cierres provienen del cálculo Lambda inventado por Alonzo Church en los años 30 antes de que existieran las primeras computadoras electrónicas, esta es la fuente de la que estoy hablando.

Lambda Calculus es el lenguaje de programación más simple del mundo. Las únicas cosas que puedes hacer en él: ►

  • APLICACIÓN: Aplicar una expresión a otra, denotada f x.
    (Piense en ello como una llamada a función , donde festá la función y xes su único parámetro)
  • RESUMEN: Vincula un símbolo que aparece en una expresión para marcar que este símbolo es solo una "ranura", un cuadro en blanco que espera ser llenado con valor, una "variable" por así decirlo. Se realiza anteponiendo una letra griega λ(lambda), luego el nombre simbólico (por ejemplo x), luego un punto .antes de la expresión. Esto convierte la expresión en una función que espera un parámetro .
    Por ejemplo: λx.x+2toma la expresión x+2y le dice que el símbolo xen esta expresión es una variable enlazada ; se puede sustituir con un valor que usted proporcione como parámetro.
    Tenga en cuenta que la función definida de esta manera es anónima- que no tiene un nombre, por lo que no puede hacer referencia a ella todavía, pero se puede llamar inmediatamente que (recuerde aplicación?) Mediante el suministro que el parámetro que está esperando, así: (λx.x+2) 7. Luego, la expresión (en este caso, un valor literal) 7se sustituye como xen la subexpresión x+2de la lambda aplicada, por lo que se obtiene 7+2, que luego se reduce a 9las reglas aritméticas comunes.

Así que hemos resuelto uno de los misterios:
lambda es la función anónima del ejemplo anterior λx.x+2,.


En diferentes lenguajes de programación, la sintaxis para la abstracción funcional (lambda) puede diferir. Por ejemplo, en JavaScript se ve así:

function(x) { return x+2; }

e inmediatamente puede aplicarlo a algún parámetro como este:

(function(x) { return x+2; })(7)

o puede almacenar esta función anónima (lambda) en alguna variable:

var f = function(x) { return x+2; }

que efectivamente le da un nombre f, lo que le permite consultarlo y llamarlo varias veces más tarde, por ejemplo:

alert(  f(7) + f(10)  );   // should print 21 in the message box

Pero no tenías que nombrarlo. Podrías llamarlo de inmediato:

alert(  function(x) { return x+2; } (7)  );  // should print 9 in the message box

En LISP, las lambdas se hacen así:

(lambda (x) (+ x 2))

y puede llamar a tal lambda aplicándola inmediatamente a un parámetro:

(  (lambda (x) (+ x 2))  7  )


Bien, ahora es el momento de resolver el otro misterio: qué es un cierre . Para hacerlo, hablemos de los símbolos ( variables ) en las expresiones lambda.

Como dije, lo que hace la abstracción lambda es unir un símbolo en su subexpresión, de modo que se convierta en un parámetro sustituible . Tal símbolo se llama obligado . Pero, ¿y si hay otros símbolos en la expresión? Por ejemplo: λx.x/y+2. En esta expresión, el símbolo xestá obligado por la abstracción lambda que lo λx.precede. Pero el otro símbolo, yno está limitado, es gratis . No sabemos qué es y de dónde viene, así que no sabemos qué significa y qué valor representa, y por lo tanto no podemos evaluar esa expresión hasta que descubramos qué ysignifica.

De hecho, lo mismo ocurre con los otros dos símbolos, 2y +. Es solo que estamos tan familiarizados con estos dos símbolos que generalmente olvidamos que la computadora no los conoce y tenemos que decirle lo que significan definiéndolos en algún lugar, por ejemplo, en una biblioteca o en el propio lenguaje.

Puede pensar en los símbolos libres como se define en otro lugar, fuera de la expresión, en su "contexto circundante", que se llama su entorno . El entorno podría ser una expresión más grande de la que forma parte esta expresión (como dijo Qui-Gon Jinn: "Siempre hay un pez más grande";)), o en alguna biblioteca, o en el lenguaje mismo (como primitivo ).

Esto nos permite dividir las expresiones lambda en dos categorías:

  • Expresiones CERRADAS: cada símbolo que aparece en estas expresiones está sujeto a alguna abstracción lambda. En otras palabras, son independientes ; no requieren que se evalúe ningún contexto circundante. También se les llama combinadores .
  • Expresiones ABIERTAS: algunos símbolos en estas expresiones no están vinculados , es decir, algunos de los símbolos que aparecen en ellos son libres y requieren información externa, por lo que no pueden evaluarse hasta que proporcione las definiciones de estos símbolos.

Puede CERRAR una expresión lambda abierta suministrando el entorno , que define todos estos símbolos libres uniéndolos a algunos valores (que pueden ser números, cadenas, funciones anónimas, también conocidas como lambdas, lo que sea ...).

Y aquí viene la parte de cierre :
el cierre de una expresión lambda es este conjunto particular de símbolos definidos en el contexto externo (entorno) que dan valores a los símbolos libres en esta expresión, haciéndolos ya no libres. Convierte una expresión lambda abierta , que todavía contiene algunos símbolos libres "indefinidos", en una cerrada , que ya no tiene símbolos libres.

Por ejemplo, si tiene la siguiente expresión lambda:, λx.x/y+2el símbolo xestá enlazado, mientras que el símbolo yestá libre, por lo tanto, la expresión es openy no puede evaluarse a menos que diga qué ysignifica (y lo mismo con +y 2, que también están libres). Pero suponga que también tiene un entorno como este:

{  y: 3,
+: [built-in addition],
2: [built-in number],
q: 42,
w: 5  }

Este entorno suministros definiciones para todos los símbolos "indefinido" (libres) de nuestro expresión lambda ( y, +, 2), y varios símbolos adicionales ( q, w). Los símbolos que necesitamos definir son este subconjunto del entorno:

{  y: 3,
+: [built-in addition],
2: [built-in number]  }

y este es precisamente el cierre de nuestra expresión lambda:>

En otras palabras, cierra una expresión lambda abierta. Aquí es de donde vino el cierre del nombre en primer lugar, y es por eso que las respuestas de tantas personas en este hilo no son del todo correctas: P


Entonces, ¿por qué están equivocados? ¿Por qué tantos de ellos dicen que los cierres son algunas estructuras de datos en la memoria, o algunas características de los lenguajes que usan, o por qué confunden los cierres con lambdas? :PAGS

Bueno, los marketoides corporativos de Sun / Oracle, Microsoft, Google, etc. tienen la culpa, porque eso es lo que llamaron estas construcciones en sus lenguajes (Java, C #, Go, etc.). A menudo llaman "cierres" lo que se supone que son solo lambdas. O llaman a los "cierres" una técnica particular que usaron para implementar el alcance léxico, es decir, el hecho de que una función puede acceder a las variables que se definieron en su alcance externo en el momento de su definición. A menudo dicen que la función "encierra" estas variables, es decir, las captura en alguna estructura de datos para evitar que se destruyan una vez que la función externa termina de ejecutarse. Pero esto es solo una "etimología del folklore" inventada post factum y marketing, que solo hace las cosas más confusas,

Y es aún peor por el hecho de que siempre hay un poco de verdad en lo que dicen, lo que no le permite descartarlo fácilmente como falso: P Permítanme explicar:

Si desea implementar un lenguaje que use lambdas como ciudadanos de primera clase, debe permitirles usar símbolos definidos en su contexto (es decir, usar variables libres en sus lambdas). Y estos símbolos deben estar allí incluso cuando la función circundante regrese. El problema es que estos símbolos están vinculados a algún almacenamiento local de la función (generalmente en la pila de llamadas), que ya no estará allí cuando la función regrese. Por lo tanto, para que una lambda funcione de la manera esperada, debe de alguna manera "capturar" todas estas variables libres de su contexto externo y guardarlas para más adelante, incluso cuando el contexto externo se haya ido. Es decir, necesitas encontrar el cierrede su lambda (todas estas variables externas que usa) y almacénelo en otro lugar (ya sea haciendo una copia o preparando espacio para ellos por adelantado, en otro lugar que no sea en la pila). El método real que utiliza para lograr este objetivo es un "detalle de implementación" de su idioma. Lo importante aquí es el cierre , que es el conjunto de variables libres del entorno de su lambda que deben guardarse en algún lugar.

Las personas no tardaron demasiado en comenzar a llamar a la estructura de datos real que usan en las implementaciones de su lenguaje para implementar el cierre como el "cierre" en sí. La estructura generalmente se ve así:

Closure {
   [pointer to the lambda function's machine code],
   [pointer to the lambda function's environment]
}

y estas estructuras de datos se pasan como parámetros a otras funciones, se devuelven de las funciones y se almacenan en variables, para representar lambdas, y les permiten acceder a su entorno envolvente y al código de máquina para ejecutarse en ese contexto. Pero es solo una forma (una de muchas) de implementar el cierre, no el cierre en sí.

Como expliqué anteriormente, el cierre de una expresión lambda es el subconjunto de definiciones en su entorno que dan valores a las variables libres contenidas en esa expresión lambda, cerrando efectivamente la expresión (convirtiendo una expresión lambda abierta , que aún no se puede evaluar, en una expresión lambda cerrada , que luego puede evaluarse, ya que todos los símbolos contenidos en ella ahora están definidos).

Cualquier otra cosa es solo un "culto a la carga" y una "magia voo-doo" de programadores y vendedores de idiomas que desconocen las verdaderas raíces de estas nociones.

Espero que eso responda tus preguntas. Pero si tiene alguna pregunta de seguimiento, no dude en hacerla en los comentarios, y trataré de explicarla mejor.

SasQ
fuente
50
Mejor respuesta explicar las cosas de forma genérica en lugar de un lenguaje específico
Shishir Arora
39
Me encanta este tipo de enfoque al explicar las cosas. Comenzando desde el principio, explicando cómo funcionan las cosas y luego cómo se crearon los conceptos erróneos actuales. Esta respuesta debe ir a la cima.
Sharky
1
@SasQ> el cierre de una expresión lambda es el subconjunto de definiciones en su entorno que dan valores a las variables libres contenidas en esa expresión lambda <Entonces, en su estructura de datos de ejemplo, eso significa que es más apropiado decir el "puntero al entorno de la función lambda "es el cierre?
Jeff M
3
Aunque el cálculo Lambda me parece un lenguaje de máquina, debo estar de acuerdo en que es un lenguaje "encontrado" en contraste con un lenguaje "hecho". Y por lo tanto, mucho menos sujeto a convenciones arbitrarias, y mucho más adecuado para capturar la estructura subyacente de la realidad. Podemos encontrar información específica en Linq, JavaScript, F # más accesible / accesible, pero el cálculo de Lambda llega al meollo del asunto sin distracción.
StevePoling
1
Aprecio que reiteraste tu punto varias veces, con una redacción ligeramente diferente cada vez. Ayuda a reforzar el concepto. Desearía que más personas hicieran esto.
johnklawlor
175

Cuando la mayoría de las personas piensan en funciones , piensan en funciones con nombre :

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

Estos se llaman por su nombre, por supuesto:

foo(); //returns the string above

Con 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 al lambda a través de la variable a la que se le asignó:

foo();

Sin embargo, es más útil que asignar funciones anónimas a variables, pasarlas ao desde funciones de orden superior, es decir, funciones que aceptan / devuelven otras funciones. En muchos de estos casos, nombrar una función no es necesario:

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 se "cierra sobre" las variables en el ámbito donde se define la función, es decir, el cierre aún 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 incrementXa 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 se obtienen objetos con estado en la programación funcional. Como no es necesario nombrar "incrementX", puede usar una lambda en este caso:

function foo()
 { @x = 0;

   return lambda() 
           { x = x + 1;
             return x;
           };
 }
Mark Cidade
fuente
14
¿Qué idioma estás hablando aquí?
Claudiu
77
Básicamente es un seudocódigo. Hay algo de lisp y JavaScript, así como un lenguaje que estoy diseñando llamado "@" ("at"), llamado así por el operador de declaración de variable.
Mark Cidade
3
@ MarkCidade, entonces, ¿dónde está este lenguaje @? ¿Hay documentación y descarga?
Pacerier
55
¿Por qué no tomar Javascript y agregar una restricción para declarar variables con signo @? Eso ahorraría un poco de tiempo :)
Nemoden
55
@Pacerier: comencé a implementar el lenguaje: github.com/marxidad/At2015
Mark Cidade
54

No todos los cierres son lambdas y no todos los lambdas son cierres. Ambas son funciones, pero no necesariamente en la forma en 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 de declarar funciones. Las lambdas con frecuencia se pueden pasar como objetos.

Un cierre es una función que encierra su estado circundante haciendo referencia a campos externos a su cuerpo. El estado cerrado permanece a través de 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 está más cerca de la definición de cierres proporcionada 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.

Michael Brown
fuente
Entonces, ¿podríamos decir que los cierres son un subconjunto de lambdas y las lambdas son un subconjunto de funciones?
sker
Los cierres son un subconjunto de lambdas ... pero las lambdas son más especiales que las funciones normales. Como dije, las lambdas se definen en línea. Esencialmente no hay forma de hacer referencia a ellos a menos que se pasen a otra función o se devuelvan como un valor de retorno.
Michael Brown
19
Las lambdas y los cierres son cada uno un subconjunto de todas las funciones, pero solo hay una intersección entre las lambdas y los cierres, donde la parte no intersectada de los cierres se denominaría funciones que son cierres y las láminas no intersectantes son funciones autónomas con funciones totalmente independientes. variables ligadas
Mark Cidade
En mi opinión, las lambdas son conceptos más fundamentales que funciones. Realmente depende del lenguaje de programación.
Wei Qiu
15

Es tan simple como esto: lambda es una construcción de lenguaje, es decir, simplemente sintaxis para funciones anónimas; un cierre es una técnica para implementarlo, o cualquier función de primera clase, de hecho, nombrada o anónima.

Más precisamente, un cierre es cómo se representa una función de primera clase en tiempo de ejecución, como un par de su "código" y un entorno "cerrado" sobre todas las variables no locales utilizadas en ese código. De esta manera, esas variables aún son accesibles incluso cuando los ámbitos externos donde se originan ya se han salido.

Desafortunadamente, hay muchos idiomas que no admiten funciones como valores de primera clase, o solo los admiten en forma inválida. Por lo tanto, las personas a menudo usan el término "cierre" para distinguir "lo real".

Andreas Rossberg
fuente
12

Desde el punto de 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 forma en que puede construir la expresión lamdba, y la reducción determina el significado de la expresión lambda.

Lambda proporciona una manera de abstraer el proceso de cálculo. por ejemplo, para calcular la suma de dos números, se puede extraer un proceso que toma dos parámetros x, y y devuelve x + y. En el esquema, puedes 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 asignar un nombre a la expresión lambda, que se denominan funciones. Pero no hay mucha diferencia, pueden considerarse conceptualmente como solo azúcar de sintaxis.

Bien, ahora imagina cómo se puede implementar esto. Cada vez que aplicamos la expresión lambda a algunas expresiones, p. Ej.

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

Simplemente podemos sustituir los parámetros con la expresión a 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, siempre que queramos 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 directamente en el entorno, ¡podemos modelar los cambios de estado!

Con estos antecedentes, verifique esta función:

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

Sabemos que cuando evaluamos la expresión lambda, xy se vinculará en una nueva tabla. Pero, ¿cómo y dónde podemos buscar z? En realidad, z se llama variable libre. Debe haber un entorno externo que contenga z. De lo contrario, el significado de la expresión no se puede determinar solo vinculando x e y. 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 unido a 1 en una tabla externa. Aún obtenemos una función que acepta dos parámetros, pero el significado real de la misma también depende del entorno externo. En otras palabras, el entorno externo se cierra con las variables libres. Con la ayuda de set !, podemos hacer que la función tenga estado, 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 se basa en el 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 los pobres, ya que realmente nos gustan las funciones de primera clase.

Utilizo el esquema para ilustrar las ideas debido a que ese esquema es uno de los primeros idiomas que tiene cierres reales. Todos los materiales aquí se presentan mucho mejor 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 el lambda.

Wei Qiu
fuente
¿Entonces uno podría sustituir todos los cierres por lambdas anidadas hasta que ya no haya variables libres? En este caso, diría que los cierres podrían verse como un tipo especial de lambdas.
Trilarion
8

El concepto es el mismo que se describió anteriormente, pero si usted es de un fondo PHP, esto explica más a fondo el uso del código PHP.

$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, function ($v) { return $v > 2; });

función ($ v) {return $ v> 2; } es la definición de la función lambda. Incluso podemos almacenarlo en una variable, por lo que puede ser reutilizable:

$max = function ($v) { return $v > 2; };

$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max);

Ahora, ¿qué pasa si desea cambiar el número máximo permitido en la matriz filtrada? Tendría que escribir otra función lambda o crear un cierre (PHP 5.3):

$max_comp = function ($max) {
  return function ($v) use ($max) { return $v > $max; };
};

$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max_comp(2));

Un cierre es una función que se evalúa en su propio entorno, que tiene una o más variables enlazadas a las que se puede acceder cuando se llama a la función. Vienen del mundo de la programación funcional, donde hay una serie de conceptos en juego. Los cierres son como las funciones lambda, pero más inteligentes en el sentido de que tienen la capacidad de interactuar con variables del entorno exterior de donde se define el cierre.

Aquí hay un ejemplo más simple de cierre de PHP:

$string = "Hello World!";
$closure = function() use ($string) { echo $string; };

$closure();

Bien explicado en este artículo.

Desarrollador
fuente
7

Esta pregunta es antigua y tiene muchas respuestas.
Ahora con Java 8 y Lambda oficial que son proyectos de cierre no oficiales, revive la pregunta.

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

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

philippe lhardy
fuente
¿Cómo se implementan las Lamdas por cierre en Java? ¿Significa que la expresión de Lamdas se convierte en una clase anónima de estilo antiguo?
hackjutsu
5

Simplemente hablando, el cierre es un truco sobre el alcance, lambda es una función anónima. Podemos realizar el cierre con lambda de manera más elegante y lambda se usa a menudo como un parámetro pasado a una función superior

feilengcui008
fuente
4

Una expresión Lambda es solo una función anónima. en Java simple, por ejemplo, puedes escribirlo así:

Function<Person, Job> mapPersonToJob = new Function<Person, Job>() {
    public Job apply(Person person) {
        Job job = new Job(person.getPersonId(), person.getJobDescription());
        return job;
    }
};

donde la clase Function solo está construida en código java. Ahora puedes llamar a mapPersonToJob.apply(person)algún lugar para usarlo. ese es solo un ejemplo. Eso es una lambda antes de que hubiera sintaxis para ello. Lambdas un atajo para esto.

Cierre:

un Lambda se convierte en un cierre cuando puede acceder a las variables fuera de este alcance. Supongo que puedes decir que es mágico, mágicamente puede envolverse alrededor del entorno en el que se creó y usar las variables fuera de su alcance (alcance externo, por lo que, para ser claros, un cierre significa que una lambda puede acceder a su ALCANCE EXTERIOR.

en Kotlin, una lambda siempre puede acceder a su cierre (las variables que están en su alcance externo)

j2emanue
fuente
0

Depende de si una función utiliza una variable externa o no para realizar la operación.

Variables externas : variables definidas fuera del alcance de una función.

  • Las expresiones lambda no tienen estado porque depende de parámetros, variables internas o constantes para realizar operaciones.

    Function<Integer,Integer> lambda = t -> {
        int n = 2
        return t * n 
    }
    
  • Los cierres mantienen el estado porque utiliza variables externas (es decir, variables definidas fuera del alcance del cuerpo de la función) junto con parámetros y constantes para realizar operaciones.

    int n = 2
    
    Function<Integer,Integer> closure = t -> {
        return t * n 
    }
    

Cuando Java crea el cierre, mantiene la variable n con la función para que pueda ser referenciada cuando se pasa a otras funciones o se usa en cualquier lugar.

DIPANSHU GOYAL
fuente