¿Qué es esta 'Lambda' de la que todo el mundo sigue hablando?

93

¿Qué es esta 'Lambda' de la que todo el mundo sigue hablando? Parece que a mucha gente le encanta, pero todo lo que puedo deducir de él es que es solo una forma de agrupar muchas líneas de código en una sola expresión.

¿Puede alguien aclararme sobre su verdadero valor?

Josh Hunt
fuente
16
¿Puedo señalar a los que responden que el que preguntó en ninguna parte menciona .net
1
verifique esto relacionado qn stackoverflow.com/questions/16501/what-is-a-lambda-function
yesraaj
Pregunta crujiente. Gracias por preguntar.
Maní
Las lambdas pertenecen al mundo de la programación funcional (programación declarativa).
RBT

Respuestas:

179

Funciones sin nombre

En pocas palabras, una lambda es una función sin nombre o una función anónima. Un pequeño fragmento de código ejecutable, que se puede pasar como si fuera una variable. En JavaScript:

function () {}; // very simple

Veamos ahora algunos usos de estas lambdas.

Resumen de código repetitivo

Las lambdas se pueden utilizar para abstraer el código repetitivo. Por ejemplo, bucles. Estamos acostumbrados a escribir fory whilebucles todo el día. Pero este es un código que no se escribe. Podríamos extraer el código dentro del ciclo, la parte más importante del ciclo, y abstraer el resto:

for (var i=0; i<array.length; i++) {
    // do what something useful with array[i]
}

mediante el uso de la forEachmatriz de objetos, se convierte en:

array.forEach(function (element, index) {
   // do something useful with element
   // element is the equivalent of array[i] from above
});

La abstracción anterior puede no ser tan útil, pero hay otras funciones de orden superior, como forEach, que realizan tareas mucho más útiles. Por ejemplo filter:

var numbers = [1, 2, 3, 4];
var even    = [];

// keep all even numbers from above array
for (var i=0; i<numbers.length; i++) {
    if (numbers[i] % 2 === 0) {
        even.push(numbers[i]);
    }
}

alert(even);

// Using the filter method
even = [1, 2, 3, 4].filter(function (number) {
    return number % 2 === 0;
});

alert(even);

Retraso en la ejecución del código

En algunos entornos, en los que el concepto de evento está disponible, podríamos usar lambdas para responder a eventos que pueden ocurrir en algún momento.

window.onload = function () {
    alert("Loaded");
};

window.setTimeout(function () {
    alert("Code executed after 2 seconds.");
}, 2000);

Esto podría haberse hecho de otras formas, pero son bastante detalladas. Por ejemplo, en Java existe elRunnable interfaz.

Fábricas de funciones

Hasta este punto, solo usamos lambdas principalmente por sus capacidades sintácticas de azúcar. Pero hay situaciones en las que las lambdas pueden ser mucho más útiles. Por ejemplo, podemos tener funciones que devuelvan lambdas. Digamos que tenemos una función que queremos que sus valores de retorno se almacenen en caché.

var users = [];
var getUser = function (name) {
    if (! users[name]) {
        // expensive operations to get a user. Ajax for example
        users[name] = user_from_ajax;
    }

    return users[name];
};

Más adelante, podemos notar que tenemos una función similar:

var photos = [];
var getPhoto = function (name) {
    if (! photo[name]) {
        // expensive operations to get a user. Ajax for example
        photos[name] = photo_from_ajax;
    }

    return photos[name];
};

Claramente hay un patrón ahí, así que vamos a abstraerlo. El uso de Let memoization .

/**
 * @param {Array}     store Data structure in which we cache lambda's return values
 * @param {Function}  lambda
 * @return {Function} A function that caches the result of calling the lambda param
 */
var memoize = function (store, lambda) {
    // return a new lambda
    return function (name) {
        if (! store[name]) {
            // Execute the lambda and cache the result
            store[name] = lambda(name);
        }

        return store[name];
    };
};

var getUsers = memoize([], function (name) {
    // expensive operations to get a user. Ajax for example
});

var getPhotos = memoize([], function (name) {
    // expensive operations to get a photo. Ajax for example
});

Como puede ver, al usar lambdas, pudimos abstraer la lógica de almacenamiento en caché / memorización. Si para el otro ejemplo hubiera algunas soluciones, creo que este problema en particular difícilmente se resuelve con otras técnicas. Logramos extraer un código repetitivo importante en un solo lugar. Sin mencionar que nos deshicimos del usersyphotos variables globales .

Al mirar su perfil, veo que es principalmente un usuario de Python. Para el patrón anterior, Python tiene el concepto de decoradores. Hay muchos ejemplos en la red para decoradores de memorias . La única diferencia es que en Python lo más probable es que tenga una función anidada con nombre dentro de esa función decoradora. La razón es que Python solo admite lambdas de expresión única. Pero el concepto es el mismo.

Como ejemplo del uso de Python lambda. El código anterior en el que filtramos números pares se puede representar en Python de esta manera:

filter(lambda x: x % 2 == 0, [1, 2, 3, 4])

De todos modos, las lambdas no son tan poderosas sin cierres. Los cierres es lo que hace que el concepto de lambdas sea tan poderoso. En mi ejemplo de memorización, he utilizado cierres para crear un cierre alrededor del storeparámetro. De esta manera, tengo acceso a ese parámetro incluso después de que la memoizefunción haya devuelto su resultado (una lambda).

Ionuț G. Stan
fuente
3
Vaya, le dedicaste mucho tiempo.
mk12
4
@ Mk12, en la redacción real de la respuesta, no realmente. Al aprender estas cosas, sí, ha pasado algún tiempo desde que comencé :)
Ionuț G. Stan
Buena respuesta pero falta información sobre "interfaces funcionales" (desde el punto de vista de Java).
djangofan
¿Cuáles son esos operadores "===" en su "Código repetitivo de abstracción"?
Don
@Don ver esto stackoverflow.com/questions/359494/…
Ionuț G. Stan
19

El término "lambda" se usa para referirse a una función anónima, generalmente un cierre . Son útiles porque le permiten escribir funciones que usan otras funciones sin sobrecargar su código innecesariamente. Por ejemplo, en Ruby:

(1..100).select {|num| num % 2 == 0}

Esto creará una matriz que contiene los números pares entre 1 y 100. No tenemos que escribir un ciclo explícito - el método de selección toma una función que usa para probar los valores, así que todo lo que necesitamos es nuestra lógica personalizada. Esto nos permite personalizar en gran medida el método sin prácticamente ningún esfuerzo ni gastos generales. Básicamente, podemos componer funciones a partir de funciones más pequeñas.

Ese es solo un ejemplo sencillo de lo que pueden hacer. La capacidad de pasar funciones como datos es realmente poderosa y los programadores de lenguajes funcionales rutinariamente hacen cosas realmente sorprendentes con ella.

Arrojar
fuente
6
Tal vez debería agregar que lo que está dentro de las tuberías es el parámetro. Soy una de esas personas que tiene problemas para leer ruby.
Skurmedel
Esta es una buena respuesta. La única razón por la que Ionut obtuvo mi voto es que nos dijo por qué deberíamos preocuparnos (en detalle) por las lambdas.
Frank Shearar
No estaría de acuerdo en que las lambdas suelen ser cierres.
jwg
6

"Lambda" quizás demasiado pocos. Eche un vistazo al cálculo Lambda . Es útil en programación funcional.

Y la programación funcional es otro paradigma de programación (como procedimental u orientada a objetos).

HOLA
fuente
5
Entonces la gente habla de "Lambda", lo más probable es que estén hablando de función anónima, punteros de función, cierre o algo similar. Casi nunca se refieren al verdadero cálculo lambda.
J-16 SDiZ
Me alegro de que hayas mencionado el cálculo Lambda. +1.
RBT
5

Las lambdas en .NET a menudo se denominan "azúcar sintáctico". No afectan directamente la funcionalidad, sin embargo, facilitan el uso del idioma para las personas.

Cuando haya entendido el poder de usarlos, estoy seguro de que encontrará que estará escribiendo menos código en comparación con el estilo antiguo usando métodos delegados / anónimos.

cuadrado rojo
fuente
1
No creo que nadie haya mencionado .NET, por lo que el OP probablemente esté mejor con una respuesta más general.
molf
2
es por eso que aclaré con la respuesta que se trata de .net. Si otros se animan con la implementación de su idioma, las preguntas y respuestas ayudarán a muchas personas sin importar el idioma que elijan.
redsquare
Esta respuesta se lee como si hubiera escuchado algo sobre lambdas, pero usted mismo aún no las comprende.
jwg
2

Dr Dobbs Journal tiene un artículo útil que presenta expresiones lambda (dentro del contexto de C ++, pero creo que puede aplicar los principios a cualquier lenguaje).

Como dice el artículo: "Una expresión lambda es una expresión muy compacta que no requiere una definición de función / clase separada".

Entonces, usando los ejemplos de listados 1 y 2 de DDJ en lugar de escribir:

std::for_each( vec.begin(), vec.end(), print_to_stream<std::string>(std::cout));

Lo que requiere una definición de clase separada como:

template <typename T, typename Stream> class print_to_stream_t {
  Stream& stream_;
public:
  print_to_stream_t(Stream& s):stream_(s) {}
  void operator()(const T& t) const {
    stream_ << t;
  }
};
template <typename T,typename Stream> 
print_to_stream_t<T,Stream>   print_to_stream(Stream& s) {
  return print_to_stream_t<T,Stream>(s);
}

Usando la biblioteca Boost lambda, esto puede convertirse en:

std::for_each(vec.begin(),vec.end(),std::cout << _1);

Lo que mantiene la definición en línea.

El artículo también explica algunas aplicaciones más de expresiones lambda.

Creo que un punto clave en el artículo de DDJ es "Normalmente, las expresiones lambda se utilizan cuando se necesitan funciones pequeñas y no demasiado complejas en el sitio de la llamada. Si la función no fuera trivial, no querría una expresión lambda sino una función normal o un objeto de función ".

danio
fuente
2

Si alguna vez ha trabajado con funciones / métodos que usan punteros de función, delegados, estrategia o manejo de patrones / eventos de observador, y pensó para sí mismo "Estoy escribiendo toda esta función solo para usarla una sola vez, para pasarla a este método ; Desearía poder escribirlo en su lugar, en lugar de desordenar mi código ", ahí es donde puede usar las funciones Lambda. Los lenguajes que admiten esta construcción también suelen aprovechar en gran medida el concepto de pasar funciones como parámetros, particularmente en lo que respecta al trabajo con listas (funciones de primera clase y funciones de orden superior). Esto es especialmente cierto para los lenguajes funcionales, que se basan en la composición de funciones en lugar de la modificación de la memoria para los cálculos. En algunos casos (en lenguajes como Python),

TR
fuente
2

'lambda' qua palabra es la terminología de los días en que los tipos de ciencias de la computación tenían más probabilidades de estar capacitados en matemáticas o lógica que tener un título en ciencias de la computación. Algunos de ellos crearon un paradigma llamado "programación funcional", bastante diferente del imperativo y bastante poderoso también. hasta donde se ese es el medio donde el término entró en uso.

Los matemáticos y los lógicos suelen utilizar palabras extrañas.

'lambda' suena realmente esotérico, como si fueran algo muy extraño y especial. Realmente, si escribe JavaScript para una aplicación de navegador web y usa el modismo "var foo = function () {...}", ha estado usando funciones lambda todo el tiempo.

Peter Mortensen
fuente
1

Una expresión lambda es una forma simple de función. La idea es que algo de la forma de la izquierda (equivalente a parámetros) se convierta en algo de la forma de la derecha (equivalente al cuerpo).

por ejemplo, en do sostenido:

x => x * x

es una lambda para elevar al cuadrado un valor. Algo de la forma

x

se convierte en algo de la forma

x * x
Dave Cousineau
fuente
0

"Una expresión lambda es una función anónima que puede contener expresiones y declaraciones, y puede usarse para crear delegados o tipos de árboles de expresión.

Todas las expresiones lambda usan el operador lambda =>, que se lee como "va a". El lado izquierdo del operador lambda especifica los parámetros de entrada (si los hay) y el lado derecho contiene el bloque de expresión o declaración. La expresión lambda x => x * x se lee "x va ax veces x".

de MSDN

Fermin
fuente
4
Sí, Microsoft hace que todos piensen que lo han inventado. Sin embargo, las expresiones lambda son anteriores a Microsoft. Es un término matemático que se ha aplicado a varios lenguajes de programación. (Lo cual es posible, ya que las matemáticas podrían considerarse un lenguaje de computadora en sí mismas.)
Wim ten Brink
4
Tenga en cuenta que esto es específico de la implementación .Net de Microsoft. No es una gran desviación de la idea general de una lambda, pero creo que la funcionalidad implementada en Lisp es más "estándar".
Chuck
2
Esa respuesta no explica en absoluto qué es un Lambda (necesita definiciones de función anónima, delegado, tipo de árbol de expresión) y ciertamente no explica cuál es su valor.
danio
0

Para obtener una explicación completa sobre las expresiones Lambda, consulte también Wikipedia . (Desplácese hacia abajo hasta el cálculo Lambda y los lenguajes de programación parte de .) Las expresiones Lambda no son tan nuevas y no son solo parte de C #, ¡sino algo que se introdujo en la informática hace casi 80 años! Las expresiones lambda son la base de la programación funcional.

¿Es valioso? Bueno, considerando que en realidad es bastante antiguo, diría: muy valioso para cualquiera que haga cálculos.

Wim ten Brink
fuente
0

Si le gusta Java, ha escuchado mucho sobre lambdas o cierres en los últimos meses, porque hubo diferentes propuestas para agregar esta característica a Java 7. Sin embargo, creo que el comité lo dejó. Una de las propuestas es de Neal Gafter y se explica con gran detalle aquí: javac.info . Esto me ayudó a comprender los casos de uso y las ventajas (especialmente sobre las clases internas)

Tim Büthe
fuente
0

Encontrará todo lo que necesita saber (sobre C # Lambdas) para comenzar aquí:
Expresiones Lambda

Robert Koritnik
fuente
-1

Sí, es solo una forma de agrupar muchas líneas de código en una sola expresión. Pero al ser un abarrotamiento tan eficiente, permite algunas formas nuevas de estructurar su programa.

A menudo, uno evitaría escribir delegados o devoluciones de llamada y volver al estilo de procedimiento simplemente porque es demasiado trabajo declarar nuevas funciones o clases para una sola expresión.

Las expresiones lambda hacen que valga la pena usar devoluciones de llamada incluso para las tareas más pequeñas, lo que podría hacer que el código sea más claro. Tal vez no.

ima
fuente