O que é uma lambda (função)?


Respostas:


1081

O Lambda é derivado do Cálculo do Lambda e refere-se a funções anônimas na programação.

Por que isso é legal? Ele permite que você escreva funções de descarte rápido sem nomeá-las. Ele também fornece uma boa maneira de escrever fechamentos. Com esse poder, você pode fazer coisas assim.

Pitão

def adder(x):
    return lambda y: x + y
add5 = adder(5)
add5(1)
6

Como você pode ver no snippet do Python, o adicionador de função recebe um argumento x e retorna uma função anônima, ou lambda, que usa outro argumento y. Essa função anônima permite criar funções a partir de funções. Este é um exemplo simples, mas deve transmitir a potência que os lambdas e os fechamentos têm.

Exemplos em outros idiomas

Perl 5

sub adder {
    my ($x) = @_;
    return sub {
        my ($y) = @_;
        $x + $y
    }
}

my $add5 = adder(5);
print &$add5(1) == 6 ? "ok\n" : "not ok\n";

Javascript

var adder = function (x) {
    return function (y) {
        return x + y;
    };
};
add5 = adder(5);
add5(1) == 6

JavaScript (ES6)

const adder = x => y => x + y;
add5 = adder(5);
add5(1) == 6

Esquema

(define adder
    (lambda (x)
        (lambda (y)
           (+ x y))))
(define add5
    (adder 5))
(add5 1)
6

C # 3.5 ou superior

Func<int, Func<int, int>> adder = 
    (int x) => (int y) => x + y; // `int` declarations optional
Func<int, int> add5 = adder(5);
var add6 = adder(6); // Using implicit typing
Debug.Assert(add5(1) == 6);
Debug.Assert(add6(-1) == 5);

// Closure example
int yEnclosed = 1;
Func<int, int> addWithClosure = 
    (x) => x + yEnclosed;
Debug.Assert(addWithClosure(2) == 3);

Rápido

func adder(x: Int) -> (Int) -> Int{
   return { y in x + y }
}
let add5 = adder(5)
add5(1)
6

PHP

$a = 1;
$b = 2;

$lambda = fn () => $a + $b;

echo $lambda();

Haskell

(\x y -> x + y) 

Java veja este post

// The following is an example of Predicate : 
// a functional interface that takes an argument 
// and returns a boolean primitive type.

Predicate<Integer> pred = x -> x % 2 == 0; // Tests if the parameter is even.
boolean result = pred.test(4); // true

Lua

adder = function(x)
    return function(y)
        return x + y
    end
end
add5 = adder(5)
add5(1) == 6        -- true

Kotlin

val pred = { x: Int -> x % 2 == 0 }
val result = pred(4) // true

Rubi

Ruby é um pouco diferente, pois você não pode chamar um lambda usando exatamente a mesma sintaxe que chamar uma função, mas ainda possui lambdas.

def adder(x)
  lambda { |y| x + y }
end
add5 = adder(5)
add5[1] == 6

Ruby sendo Ruby, existe uma abreviação para lambdas, então você pode definir adderdesta maneira:

def adder(x)
  -> y { x + y }
end

R

adder <- function(x) {
  function(y) x + y
}
add5 <- adder(5)
add5(1)
#> [1] 6

3
Qual é a diferença, então, entre uma função lambda e um functor ?
Maxpm 8/11

1
@Maxpm um functor pode ser um objeto padrão com campos e funções de instância, enquanto uma função lambda geralmente consiste apenas em uma linha de instruções. Isso pode variar dependendo do idioma do curso.
Zdimension

1
Eu não acho que seja necessariamente preciso dizer que as funções lambda são iguais às funções anônimas. Para alguns idiomas como JavaScript, uma expressão lambda é uma forma específica de uma função anônima. O exemplo de JavaScript que você forneceu é uma função anônima sem sintaxe lambda, enquanto o exemplo de JavaScript (ES6) que você forneceu é uma expressão lambda.
Kyle Delaney

1
@KyleDelaney fato, anônimo não é uma condição necessária para ser um lambda, na verdade existem função lambda que não são anônimos, como você aponta lá um mesmo no exemplo
Carmine Tambascia

@AliAnkarali ou se acostumar a usar rubys lambda;)
Jimmy MG Lim

107

Um lambda é um tipo de função definida em linha. Juntamente com um lambda, você também costuma ter algum tipo de variável que pode conter uma referência a uma função, lambda ou de outra forma.

Por exemplo, aqui está um código C # que não usa um lambda:

public Int32 Add(Int32 a, Int32 b)
{
    return a + b;
}

public Int32 Sub(Int32 a, Int32 b)
{
    return a - b;
}

public delegate Int32 Op(Int32 a, Int32 b);

public void Calculator(Int32 a, Int32 b, Op op)
{
    Console.WriteLine("Calculator: op(" + a + ", " + b + ") = " + op(a, b));
}

public void Test()
{
    Calculator(10, 23, Add);
    Calculator(10, 23, Sub);
}

Isso chama a Calculadora, transmitindo não apenas dois números, mas qual método chamar dentro da Calculadora para obter os resultados do cálculo.

No C # 2.0, temos métodos anônimos, que reduzem o código acima para:

public delegate Int32 Op(Int32 a, Int32 b);

public void Calculator(Int32 a, Int32 b, Op op)
{
    Console.WriteLine("Calculator: op(" + a + ", " + b + ") = " + op(a, b));
}

public void Test()
{
    Calculator(10, 23, delegate(Int32 a, Int32 b)
    {
        return a + b;
    });
    Calculator(10, 23, delegate(Int32 a, Int32 b)
    {
        return a - b;
    });
}

E então, no C # 3.0, temos lambdas, o que torna o código ainda mais curto:

public delegate Int32 Op(Int32 a, Int32 b);

public void Calculator(Int32 a, Int32 b, Op op)
{
    Console.WriteLine("Calculator: op(" + a + ", " + b + ") = " + op(a, b));
}

public void Test()
{
    Calculator(10, 23, (a, b) => a + b);
    Calculator(10, 23, (a, b) => a - b);
}

Em vez de definir explicitamente o delegado Op, pode-se simplesmente usarFunc<int, int>
Mateen Ulhaq

Eu sugeriria Console.WriteLine("Calculator: op " + op.Method.Name + " (" + a + ", " + b + ") = " + op(a, b));o primeiro exemplo.
Marc.2377

Tão surpreendente quanto a resposta aceita é ajudar pessoas em vários idiomas diferentes, sinto que essa resposta me ajuda a entender melhor a vantagem das lambdas e como elas são diferentes de uma função padrão. Eu posso ver claramente aqui a vantagem de um lambda sobre os métodos anteriores para obter um resultado semelhante.
RTHarston

Obrigado pelo seu exemplo, ter uma função mais complexa ajuda a entender as vantagens das lambdas muito mais do que funções simples, onde parece que você não recebe muita otimização
Sarah

71

O nome "lambda" é apenas um artefato histórico. Estamos falando apenas de uma expressão cujo valor é uma função.

Um exemplo simples (usando Scala para a próxima linha) é:

args.foreach(arg => println(arg))

onde o argumento para o foreachmétodo é uma expressão para uma função anônima. A linha acima é mais ou menos a mesma coisa que escrever algo assim (código não muito real, mas você entenderá):

void printThat(Object that) {
  println(that)
}
...
args.foreach(printThat)

exceto que você não precisa se preocupar com:

  1. Declarando a função em outro lugar (e tendo que procurá-la quando você revisitar o código posteriormente).
  2. Nomeando algo que você está usando apenas uma vez.

Depois que você estiver acostumado a funcionar com valores, ficar sem eles parece tão tolo quanto precisar nomear todas as expressões, como:

int tempVar = 2 * a + b
...
println(tempVar)

em vez de apenas escrever a expressão onde você precisar:

println(2 * a + b)

A notação exata varia de idioma para idioma; Grego nem sempre é necessário! ;-)


62

Refere-se ao cálculo lambda , que é um sistema formal que apenas possui expressões lambda, que representam uma função que utiliza uma função para seu único argumento e retorna uma função. Todas as funções no cálculo lambda são desse tipo, ou seja λ : λ → λ,.

Lisp usou o conceito lambda para nomear seus literais de função anônimos. Este lambda representa uma função que recebe dois argumentos, xey, e retorna seu produto:

(lambda (x y) (* x y)) 

Pode ser aplicado em linha assim (avalia para 50 ):

((lambda (x y) (* x y)) 5 10)

Eu acho que seu uso λ : λ -> λé confuso (e inválido, na verdade).
einpoklum

51

O cálculo lambda é uma teoria matemática consistente de substituição. Na matemática da escola, vê-se, por exemplo, x+y=5emparelhado x−y=1. Juntamente com as formas de manipular equações individuais, também é possível reunir as informações dessas duas, desde que as substituições de equações cruzadas sejam feitas logicamente. O cálculo Lambda codifica a maneira correta de fazer essas substituições.

Dado que y = x−1é um rearranjo válido da segunda equação, isso: λ y = x−1significa uma função que substitui os símbolos x−1pelo símbolo y. Agora imagine aplicar λ ya cada termo na primeira equação. Se um termo for y, execute a substituição; caso contrário, não faça nada. Se você fizer isso no papel, verá como a aplicação disso λ ytornará a primeira equação solucionável.

Essa é uma resposta sem qualquer ciência da computação ou programação.

O exemplo de programação mais simples que consigo pensar vem de http://en.wikipedia.org/wiki/Joy_(programming_language)#How_it_works :

Aqui está como a função quadrada pode ser definida em uma linguagem de programação imperativa (C):

int square(int x)
{
    return x * x;
}

A variável x é um parâmetro formal que é substituído pelo valor real a ser elevado ao quadrado quando a função é chamada. Em uma linguagem funcional (esquema), a mesma função seria definida:

(define square
  (lambda (x) 
    (* x x)))

Isso é diferente em muitos aspectos, mas ainda usa o parâmetro formal x da mesma maneira.


Adicionado: http://imgur.com/a/XBHub

lambda


14

Ligeiramente simplificado: uma função lambda é aquela que pode ser passada para outras funções e é acessada pela lógica.

No C #, a sintaxe lambda geralmente é compilada para métodos simples da mesma maneira que os delegados anônimos, mas também pode ser dividida e sua lógica lida.

Por exemplo (em C # 3):

LinqToSqlContext.Where( 
    row => row.FieldName > 15 );

O LinqToSql pode ler essa função (x> 15) e convertê-la no SQL real para executar usando árvores de expressão.

A afirmação acima se torna:

select ... from [tablename] 
where [FieldName] > 15      --this line was 'read' from the lambda function

Isso é diferente dos métodos normais ou dos delegados anônimos (que são apenas magias do compilador), porque eles não podem ser lidos .

Nem todos os métodos em C # que usam sintaxe lambda podem ser compilados para árvores de expressão (ou seja, funções reais lambda). Por exemplo:

LinqToSqlContext.Where( 
    row => SomeComplexCheck( row.FieldName ) );

Agora a árvore de expressão não pode ser lida - SomeComplexCheck não pode ser dividido. A instrução SQL será executada sem o where e todas as linhas dos dados serão inseridas SomeComplexCheck.

As funções Lambda não devem ser confundidas com métodos anônimos. Por exemplo:

LinqToSqlContext.Where( 
    delegate ( DataRow row ) { 
        return row.FieldName > 15; 
    } );

Isso também tem uma função 'inline', mas desta vez é apenas mágica do compilador - o compilador C # dividirá isso em um novo método de instância com um nome gerado automaticamente.

Os métodos anônimos não podem ser lidos e, portanto, a lógica não pode ser traduzida como nas funções lambda.



7

Um exemplo de lambda em Ruby é o seguinte:

hello = lambda do
    puts('Hello')
    puts('I am inside a proc')
end

hello.call

Irá gerar a seguinte saída:

Hello
I am inside a proc

5

@ Brian Eu uso lambdas o tempo todo em C #, em operadores LINQ e não LINQ. Exemplo:

string[] GetCustomerNames(IEnumerable<Customer> customers)
 { return customers.Select(c=>c.Name);
 }

Antes do C #, eu usava funções anônimas em JavaScript para retornos de chamada para funções AJAX, antes do termo Ajax ser cunhado:

getXmlFromServer(function(result) {/*success*/}, function(error){/*fail*/});

O interessante da sintaxe lambda do C #, porém, é que, por si só, seu tipo não pode ser inferido (ou seja, você não pode digitar var foo = (x, y) => x * y), mas dependendo de qual tipo eles são atribuídos a eles, eles serão compilados como delegados ou árvores de sintaxe abstrata que representam a expressão (é assim que os mapeadores de objetos LINQ fazem sua mágica "integrada ao idioma").

Lambdas no LISP também podem ser passadas para um operador de cotação e depois percorridas como uma lista de listas. Algumas macros poderosas são criadas dessa maneira.


5

A pergunta é formalmente respondida bastante, por isso não tentarei acrescentar mais sobre isso.

Em palavras muito simples e informais para alguém que sabe muito pouco ou nada sobre matemática ou programação, eu explicaria isso como uma pequena "máquina" ou "caixa" que recebe alguma entrada, faz algum trabalho e produz alguma saída, sem nome específico , mas sabemos onde está e, justamente por esse conhecimento, nós o usamos.

Na prática, para uma pessoa que sabe o que é uma função, eu diria a ela que é uma função que não tem nome, geralmente colocada em um ponto na memória que pode ser usado apenas fazendo referência a essa memória (geralmente através do uso de uma variável - se eles ouviram falar sobre o conceito de ponteiros de função, eu os usaria como um conceito semelhante) - esta resposta cobre os princípios básicos (sem menção de fechamentos etc.), mas é possível entender o ponto facilmente.



4

Só porque não consigo ver um exemplo de C ++ 11 aqui, vou adiante e postarei este bom exemplo daqui . Após a pesquisa, é o exemplo específico de idioma mais claro que eu pude encontrar.

Olá, Lambdas, versão 1

template<typename F>

void Eval( const F& f ) {
        f();
}
void foo() {
        Eval( []{ printf("Hello, Lambdas\n"); } );
}

Olá, Lambdas, versão 2:

void bar() {
    auto f = []{ printf("Hello, Lambdas\n"); };
    f();
}

3

Tenho problemas para entender expressões lambda porque trabalho no Visual FoxPro, que possui substituição de macro e as funções ExecScript {} e Evaluate (), que parecem servir ao mesmo propósito.

? Calculator(10, 23, "a + b")
? Calculator(10, 23, "a - b");

FUNCTION Calculator(a, b, op)
RETURN Evaluate(op)

Um benefício definitivo do uso de lambdas formais é (presumo) a verificação em tempo de compilação: a Fox não saberá se você digitar a sequência de texto acima até tentar executá-la.

Isso também é útil para código orientado a dados: você pode armazenar rotinas inteiras em campos de memorando no banco de dados e apenas avaliá-las em tempo de execução. Isso permite que você ajuste parte do aplicativo sem realmente ter acesso à fonte. (Mas esse é outro tópico completamente.)


3

Para uma pessoa sem formação em ficção científica, o que é uma lambda no mundo da Ciência da Computação?

Ilustrarei intuitivamente passo a passo em códigos python simples e legíveis.

Em resumo, um lambda é apenas uma função anônima e inline.

Vamos começar da tarefa de entender lambdascomo um calouro com conhecimentos básicos de aritmética.

O plano de atribuição é 'o nome = valor', consulte:

In [1]: x = 1
   ...: y = 'value'
In [2]: x
Out[2]: 1
In [3]: y
Out[3]: 'value'

'x', 'y' são nomes e 1, 'valor' são valores. Tente uma função em matemática

In [4]: m = n**2 + 2*n + 1
NameError: name 'n' is not defined

Relatórios de erro,
você não pode escrever uma matemática diretamente como código, 'n' deve ser definido ou atribuído a um valor.

In [8]: n = 3.14
In [9]: m = n**2 + 2*n + 1
In [10]: m
Out[10]: 17.1396

Funciona agora, e se você insistir em combinar as duas linhas seperarte em uma. Lá vemlambda

In [13]: j = lambda i: i**2 + 2*i + 1
In [14]: j
Out[14]: <function __main__.<lambda>>

Nenhum erro relatado.

Este é um relance lambda, permite que você escreva uma função em uma única linha, como na matemática diretamente no computador.

Veremos mais tarde.

Vamos continuar a aprofundar a tarefa.

Como ilustrado acima, o símbolo de igual =funciona para o tipo de dados simples (1 e 'valor') e expressão simples (n ** 2 + 2 * n + 1).

Tente o seguinte:

In [15]: x = print('This is a x')
This is a x
In [16]: x
In [17]: x = input('Enter a x: ')
Enter a x: x

Funciona para instruções simples, existem 11 tipos delas no python 7. Instruções simples - documentação do Python 3.6.3

Que tal declaração composta,

In [18]: m = n**2 + 2*n + 1 if n > 0
SyntaxError: invalid syntax
#or
In [19]: m = n**2 + 2*n + 1, if n > 0
SyntaxError: invalid syntax

Aí vem defhabilitá-lo a trabalhar

In [23]: def m(n):
    ...:     if n > 0:
    ...:         return n**2 + 2*n + 1
    ...:
In [24]: m(2)
Out[24]: 9

Tada, analise, 'm' é o nome, 'n ** 2 + 2 * n + 1' é o valor. :é uma variante de '='.
Encontre, se apenas para entender, tudo começa com a atribuição e tudo é atribuição.

Agora retorne a lambda, temos uma função chamada 'm'

Tentar:

In [28]: m = m(3)
In [29]: m
Out[29]: 16

Existem dois nomes de 'm' aqui, a função mjá tem um nome, duplicado.

Está formatando como:

In [27]: m = def m(n):
    ...:         if n > 0:
    ...:             return n**2 + 2*n + 1
    SyntaxError: invalid syntax

Não é uma estratégia inteligente, então os relatórios de erros

Temos que excluir um deles, definir uma função sem nome.

m = lambda n:n**2 + 2*n + 1

É chamado de 'função anônima'

Em conclusão,

  1. lambda em uma função embutida que permite escrever uma função em uma linha reta, como na matemática
  2. lambda é anônimo

Espero que isto ajude.


2

É uma função que não tem nome. Por exemplo, em c #, você pode usar

numberCollection.GetMatchingItems<int>(number => number > 5);

para retornar os números maiores que 5.

number => number > 5

é a parte lambda aqui. Representa uma função que pega um parâmetro (número) e retorna um valor booleano (número> 5). O método GetMatchingItems usa esse lambda em todos os itens da coleção e retorna os itens correspondentes.


2

Em Javascript, por exemplo, as funções são tratadas como o mesmo tipo misto como tudo o resto ( int, string, float, bool). Como tal, você pode criar funções em tempo real, atribuí-las a coisas e chamá-las de volta mais tarde. É útil, mas não é algo que você deseja usar em excesso ou confundirá todos que precisam manter seu código depois de você ...

Este é um código com o qual eu estava jogando para ver a profundidade dessa toca de coelho:

var x = new Object;
x.thingy = new Array();
x.thingy[0] = function(){ return function(){ return function(){ alert('index 0 pressed'); }; }; }
x.thingy[1] = function(){ return function(){ return function(){ alert('index 1 pressed'); }; }; }
x.thingy[2] = function(){ return function(){ return function(){ alert('index 2 pressed'); }; }; }

for(var i=0 ;i<3; i++)
    x.thingy[i]()()();

2

No contexto do CS, uma função lambda é um conceito matemático abstrato que aborda um problema de avaliação simbólica de expressões matemáticas. Nesse contexto, uma função lambda é igual a um termo lambda .

Mas nas linguagens de programação é algo diferente. É um pedaço de código declarado "no lugar" e que pode ser passado como um "cidadão de primeira classe". Esse conceito pareceu ser útil para que ele chegasse a quase todas as linguagens de programação modernas populares (consulte as funções lambda em todo lugar)


2

A Lambda Function, ou a Small Anonymous Function, é um bloco de funcionalidade independente que pode ser transmitido e usado em seu código. O Lambda tem nomes diferentes em diferentes linguagens de programação - Lambdaem Python e Kotlin , Closureem Swift ou Blockem C e Objective-C . Embora o significado de lambda seja bastante semelhante para essas línguas, às vezes há pequenas distinções.

Vamos ver como o Lambda (Closure) funciona no Swift 4.2 com o método classificado () - da função normal até a expressão mais curta:

let coffee: [String] = ["Cappuccino", "Espresso", "Latte", "Ristretto"]

1. Função Normal

func backward(_ n1: String, _ n2: String) -> Bool {
    return n1 > n2
}
var reverseOrder = coffee.sorted(by: backward)


// RESULT: ["Ristretto", "Latte", "Espresso", "Cappuccino"]

2. Expressão de encerramento

reverseOrder = coffee.sorted(by: { (n1: String, n2: String) -> Bool in
    return n1 > n2
})

3. Expressão de fechamento embutido

reverseOrder = coffee.sorted(by: { (n1: String, n2: String) -> Bool in return n1 > n2 } )

4. Inferindo Tipo do Contexto

reverseOrder = coffee.sorted(by: { n1, n2 in return n1 > n2 } )

5. Retornos implícitos de fechamentos de expressão única

reverseOrder = coffee.sorted(by: { n1, n2 in n1 > n2 } )

6. Nomes de argumentos abreviados

reverseOrder = coffee.sorted(by: { $0 > $1 } )

// $0 and $1 are closure’s first and second String arguments.

7. Métodos do Operador

reverseOrder = coffee.sorted(by: >)

// RESULT: ["Ristretto", "Latte", "Espresso", "Cappuccino"]

Espero que isto ajude.


1

Eu também entendi. Eu tentei em JS com este:

var addAndMult = function(x) {
        return (function(y) {
            return (function(z) {
                return (x+y)*z; 
                });
            });
        };

Ele adiciona 2 a 4 e depois reduz o resultado por 6. No entanto, às vezes acho difícil ler :(

Também criei uma função forEach interessante:

var forEach = function(arr) {
            return (function(x) {
            for (var i=0; arr[i]; i++) {
                 x(arr[i]);
             }
        });
    }

forEach ([1,2,3,4,5]) (console.log);

Esse método itera uma matriz e executa uma ação - no caso, imprimindo no console. Agora eu também entendo por que os labmdas são poderosos.


1

Na programação de computadores, lambda é um pedaço de código (declaração, expressão ou um grupo deles) que recebe alguns argumentos de uma fonte externa. Nem sempre deve ser uma função anônima - temos várias maneiras de implementá-las.

Temos uma separação clara entre expressões, afirmações e funções, que os matemáticos não possuem.

A palavra "função" na programação também é diferente - nós temos "função é uma série de etapas a serem executadas" (do latim "executar"). Em matemática, é algo sobre correlação entre variáveis.

Linguagens funcionais estão tentando ser o mais semelhante possível às fórmulas matemáticas, e suas palavras significam quase o mesmo. Mas em outras linguagens de programação, temos diferentes.


0

A pergunta foi respondida completamente, não quero entrar em detalhes. Quero compartilhar o uso ao escrever computação numérica com ferrugem.

Há um exemplo de lambda (função anônima)

let f = |x: f32| -> f32 { x * x - 2.0 };
let df = |x: f32| -> f32 { 2.0 * x };

Quando eu escrevia um módulo do método Newton-Raphson, ele era usado como derivada de primeira e segunda ordem. (Se você quiser saber o que é o método Newton – Raphson, visite " https://en.wikipedia.org/wiki/Newton%27s_method ".

A saída como a seguinte

println!("f={:.6}      df={:.6}", f(10.0), df(10.0))

f=98.000000       df=20.000000

0

Imagine que você tem um restaurante com uma opção de entrega e um pedido que precisa ser feito em menos de 30 minutos. O ponto é que os clientes geralmente não se importam se você envia comida de bicicleta com o carro ou com os pés descalços, desde que mantenha a refeição quente e amarrada. Então, vamos converter esse idioma para Javascript com funções de transporte definidas e anônimas.

Abaixo, definimos a forma de entrega, ou seja, definimos um nome para uma função:

// ES5 
var food = function withBike(kebap, coke) {
return (kebap + coke); 
};

E se usássemos funções arrow / lambda para realizar essa transferência:

// ES6    
const food = (kebap, coke) => { return kebap + coke };

Você vê que não há diferença para o cliente e não há perda de tempo para pensar em como enviar comida. Apenas envie.

Aliás, eu não recomendo o kebap com coca-cola, é por isso que os códigos superiores causam erros. Diverta-se.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.