Funções sem nome
Simplificando, um lambda é uma função sem um nome ou uma função anônima. Um pequeno pedaço de código executável, que pode ser passado como se fosse uma variável. Em JavaScript:
function () {}; // very simple
Vamos ver agora alguns usos para esses lambdas.
Abstraindo código clichê
Lambdas podem ser usados para abstrair o código clichê. Por exemplo, loops. Estamos acostumados a escrever for
e fazer while
loops o dia todo. Mas este é um código que não pode ser escrito. Poderíamos extrair o código dentro do loop, a parte mais importante do loop, e abstrair o resto:
for (var i=0; i<array.length; i++) {
// do what something useful with array[i]
}
usando os forEach
objetos da matriz, torna-se:
array.forEach(function (element, index) {
// do something useful with element
// element is the equivalent of array[i] from above
});
A abstração acima pode não ser tão útil, mas existem outras funções de ordem superior, como forEach
, que realizam tarefas muito mais úteis. Por exemplo 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);
Atraso na execução do código
Em alguns ambientes, nos quais o conceito de evento está disponível, podemos usar lambdas para responder a eventos que podem acontecer em algum momento.
window.onload = function () {
alert("Loaded");
};
window.setTimeout(function () {
alert("Code executed after 2 seconds.");
}, 2000);
Isso poderia ter sido feito de outras maneiras, mas são bastante prolixas. Por exemplo, em Java existe a Runnable
interface.
Fábricas de funções
Até este ponto, usamos lambdas principalmente por seus recursos de açúcar sintático. Mas há situações em que lambdas podem ser muito mais úteis. Por exemplo, podemos ter funções que retornam lambdas. Digamos que temos uma função para a qual queremos que seus valores de retorno sejam armazenados em cache.
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];
};
Mais tarde, podemos notar que temos uma função semelhante:
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];
};
Há claramente um padrão ali, então vamos abstraí-lo. Vamos usar memoização .
/**
* @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 você pode ver, usando lambdas, fomos capazes de abstrair a lógica de cache / memoização. Se no outro exemplo houvesse algumas soluções alternativas, acredito que este problema específico dificilmente será resolvido com outras técnicas. Conseguimos extrair alguns códigos clichê importantes em um único lugar. Sem mencionar que nos livramos das variáveis globais users
e photos
.
Olhando para o seu perfil, vejo que você é principalmente um usuário Python. Para o padrão acima, Python tem o conceito de decoradores. Existem muitos exemplos na rede para decoradores de memoização . A única diferença é que no Python você provavelmente tem uma função aninhada nomeada dentro dessa função decoradora. A razão é que Python suporta apenas lambdas de expressão única. Mas o conceito é o mesmo.
Como um exemplo de uso de lambda em Python. O código acima, no qual filtramos os números pares, pode ser representado no Python assim:
filter(lambda x: x % 2 == 0, [1, 2, 3, 4])
De qualquer forma, lambdas não são tão poderosos sem fechamentos. Fechamentos é o que torna o conceito de lambdas tão poderoso. Em meu exemplo de memoização, usei fechamentos para criar um fechamento em torno do store
parâmetro. Dessa forma, tenho acesso a esse parâmetro mesmo depois que a memoize
função retornou seu resultado (um lambda).