O que é esse 'Lambda' que todo mundo vive falando?

93

O que é esse 'Lambda' que todo mundo vive falando? Muitas pessoas parecem amá-lo, mas tudo o que posso deduzir é que é apenas uma maneira de agrupar muitas linhas de código em uma única expressão.

Alguém pode me esclarecer sobre seu verdadeiro valor?

Josh Hunt
fonte
16
Posso apontar aos respondentes que o questionador em nenhum lugar menciona .net
Quebra-cabeça. Obrigado por perguntar.
Amendoim
Lambdas pertencem ao mundo da programação funcional (programação declarativa).
RBT

Respostas:

179

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 fore fazer whileloops 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 forEachobjetos 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 Runnableinterface.

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 userse 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 storeparâmetro. Dessa forma, tenho acesso a esse parâmetro mesmo depois que a memoizefunção retornou seu resultado (um lambda).

Ionuț G. Stan
fonte
3
Uau, você dedicou muito tempo a isso.
mk12
4
@ Mk12, na redação real da resposta, não realmente. Aprendendo essas coisas, sim, já faz algum tempo desde que comecei :)
Ionuț G. Stan
Boa resposta, mas falta informação sobre "interfaces funcionais" (do ponto de vista Java).
Djangofan
O que são esses operadores "===" em seu "Código padrão de abstração"?
Don
@ Não veja este stackoverflow.com/questions/359494/…
Ionuț G. Stan
19

O termo "lambda" é usado para se referir a uma função anônima, geralmente um encerramento . Eles são úteis porque permitem que você escreva funções que usam outras funções sem sobrecarregar seu código desnecessariamente. Por exemplo, em Ruby:

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

Isso criará uma matriz contendo os números pares entre 1 e 100. Não precisamos escrever um loop explícito - o método select usa uma função que usa para testar os valores, então tudo que precisamos é nossa lógica customizada. Isso nos permite personalizar muito o método com praticamente nenhum esforço ou sobrecarga. Basicamente, podemos compor funções a partir de funções menores.

Esse é apenas um exemplo fácil do que eles podem fazer. A capacidade de passar funções como dados é realmente poderosa e os programadores de linguagens funcionais rotineiramente fazem coisas realmente incríveis com ela.

Mandril
fonte
6
Talvez você deva acrescentar que o que está dentro dos tubos é o parâmetro. Sou uma dessas pessoas que tem dificuldade para ler rubi.
Skurmedel
Esta é uma boa resposta. A única razão pela qual Ionut obteve meu voto é que ele nos disse por que devemos nos preocupar (em detalhes) com lambdas.
Frank Shearar
Não concordo que lambdas geralmente sejam encerramentos.
jwg
6

"Lambda" talvez apenas muito poucos. Dê uma olhada no cálculo Lambda . É útil na programação funcional.

E a programação funcional é outro paradigma de programação (como procedural ou orientado a objetos).

OI
fonte
5
Então as pessoas falam sobre "Lambda", provavelmente estão falando de função anônima, ponteiros de função, encerramento ou algo semelhante. Quase nunca se refere ao verdadeiro cálculo lambda.
J-16 SDiZ
Que bom que você mencionou cálculo Lambda.! +1.
RBT
5

Lambdas no .NET são freqüentemente chamados de "açúcar sintático". Eles não afetam diretamente a funcionalidade, no entanto, tornam a linguagem mais fácil para as pessoas usarem.

Quando você compreender o poder de usá-los, tenho certeza de que descobrirá que escreverá menos código em comparação com o estilo antigo usando delegados / métodos anônimos.

quadrado vermelho
fonte
1
Acho que ninguém mencionou .NET, então o OP provavelmente fica melhor com uma resposta mais geral.
molf
2
é por isso que esclareci por responder a ser sobre .net. Se outras pessoas colaborarem com a implementação de sua linguagem, as perguntas e respostas ajudarão muitas pessoas, independentemente de sua escolha de idioma.
redsquare
Esta resposta parece que você já ouviu algo sobre lambdas, mas você mesmo não os entende ainda.
jwg
2

O Dr. Dobbs Journal tem um artigo útil que apresenta expressões lambda (dentro do contexto de C ++, mas acho que você pode aplicar os princípios a qualquer linguagem).

Como diz o artigo: "Uma expressão lambda é uma expressão altamente compacta que não requer uma definição de classe / função separada."

Portanto, use os exemplos das listagens 1 e 2 do DDJ em vez de escrever:

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

O que requer uma definição de classe 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 a biblioteca Boost lambda, isso pode se tornar:

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

O que mantém a definição embutida.

O artigo também explica mais algumas aplicações de expressões lambda.

Acho que um ponto-chave no artigo DDJ é "Normalmente, as expressões lambda são usadas quando funções pequenas e não excessivamente complexas são necessárias no site da chamada. Se a função não fosse trivial, você não iria querer uma expressão lambda, mas uma função normal ou um objeto de função. "

danio
fonte
2

Se você já trabalhou com funções / métodos que usam ponteiros de função, delegados, estratégia ou manipulação de padrão / evento de observador e pensou "Estou escrevendo esta função inteira apenas para usá-la apenas uma vez - para passá-la para este método ; Eu gostaria de poder escrever no lugar, em vez de bagunçar meu código "- é onde você pode usar funções Lambda. As linguagens que suportam essa construção geralmente também tiram grande vantagem do conceito de passagem de funções como parâmetros, particularmente no que diz respeito ao trabalho com listas (funções de primeira classe e funções de ordem superior). Isso é especialmente verdadeiro para linguagens funcionais, que dependem da composição da função em vez da modificação da memória para cálculos. Em alguns casos (em linguagens como Python),

TR
fonte
2

'lambda' como palavra é a terminologia da época em que os tipos de ciência da computação eram mais propensos a ser treinados em matemática ou lógica do que a ter um diploma em ciência da computação. Alguns deles elaboraram um paradigma chamado 'programação funcional', bastante diferente do imperativo e bastante poderoso também. AFAIK é o meio onde o termo entrou em uso.

Matemáticos e lógicos costumam usar palavras estranhas.

'lambda' soa realmente esotérico - como se fosse algo muito estranho e especial. Na verdade, se você escreve JavaScript para um aplicativo de navegador da web e usa o idioma "var foo = function () {...}", está usando funções lambda o tempo todo.

Peter Mortensen
fonte
1

Uma expressão lambda é uma forma simples de função. A ideia é que algo do formulário à esquerda (equivalente a parâmetros) se torne algo do formulário à direita (equivalente ao corpo).

por exemplo, em dó sustenido:

x => x * x

é um lambda para elevar o valor ao quadrado. Algo da forma

x

torna-se algo na forma

x * x
Dave Cousineau
fonte
0

"Uma expressão lambda é uma função anônima que pode conter expressões e instruções e pode ser usada para criar delegados ou tipos de árvore de expressão.

Todas as expressões lambda usam o operador lambda =>, que é lido como "vai para". O lado esquerdo do operador lambda especifica os parâmetros de entrada (se houver) e o lado direito contém o bloco de expressão ou instrução. A expressão lambda x => x * x é lida "x vai para x vezes x."

do MSDN

Fermín
fonte
4
Sim, a Microsoft faz todos pensarem que o inventaram. As expressões lambda são anteriores à Microsoft, no entanto. É um termo matemático que foi aplicado a várias linguagens de programação. (O que é possível, já que a matemática pode ser considerada uma linguagem de computador por si só.)
Wim ten Brink
4
Observe que isso é específico para a implementação .Net da Microsoft. Não é um grande desvio da ideia geral de lambda, mas acho que a funcionalidade implementada no Lisp é mais "padrão".
Chuck
2
Essa resposta não explica em absoluto o que é um Lambda (precisa de definições de função anônima, delegado, tipo de árvore de expressão) e certamente não explica qual é seu valor.
danio
0

Para uma explicação completa sobre as expressões Lambda, verifique também a Wikipedia . (Role para baixo até o cálculo Lambda e a parte das linguagens de programação .) As expressões lambda não são tão novas e não são apenas parte do C #, mas algo que foi introduzido na computação quase 80 anos atrás! As expressões lambda são a base da programação funcional.

É valor? Bem, considerando que é bastante antigo, eu diria: muito valioso para quem faz cálculos.

Wim ten Brink
fonte
0

Se você gosta de Java, já ouviu falar muito sobre lambdas ou encerramentos nos últimos dois meses, porque havia diferentes propostas para adicionar esse recurso ao Java 7. No entanto, acho que o comitê o abandonou. Uma das propostas é de Neal Gafter e explicada em detalhes aqui: javac.info . Isso me ajudou a entender os casos de uso e vantagens (especialmente sobre classes internas)

Tim Büthe
fonte
0

Você encontrará tudo que precisa saber (sobre C # Lambdas) para começar aqui:
Expressões Lambda

Robert Koritnik
fonte
-1

Sim, é apenas uma maneira de agrupar muitas linhas de código em uma única expressão. Mas sendo um amontoado tão eficiente, ele permite algumas novas maneiras de estruturar seu programa.

Freqüentemente, evita-se escrever delegados ou retornos de chamada e reverter para o estilo procedural simplesmente porque dá muito trabalho declarar novas funções ou classes para uma única expressão.

As expressões lambda fazem com que valha a pena usar callbacks mesmo para tarefas mínimas, o que pode deixar o código mais claro. Pode não.

Eu sou um
fonte