Pular para o conteúdo principal

Lambda e a Inferência

Duas das coisas que mais me agradaram no C++ atual são: a inferência de tipo e as expressões lambda (ou simplesmente lambda).

Neste post, quero focar em 5 pontos interessantes sobre estes assuntos. São eles:

1. O que é um lambda?
2. Lambda e Functor, qual a relação entre eles?
3. Como funciona a inferência feita em um lambda?
4. Lista de captura de um lambda
5. Legibilidade interessante

O que é um lambda?


Muito resumidamente, o cálculo lambda (lambda calculus) é uma representação computacional de uma função matemática.
Ex λ: (x, y) -> 2 * x + y
No C++, o lambda é uma função com lista de captura, parâmetros e um retorno (que pode ser void).

Lambda e Functor, qual a relação entre eles?


A implementação de um lambda é a mesma implementação de um functor! Ou seja, o compilador mapeia/transforma um lambda em um functor equivalente.
O lambda tem: lista de captura, função recebendo parâmetros e um retorno
O functor tem: constructor, operador () recebendo parâmetros e um retorno
O lambda é uma maneira interessante para definir um functor anônimo.

Os dois vão virar código inline, mas qual tem a sintaxe mais amigável?
Vamos comparar as duas implementações de uma função que multiplica um valor por outro pré-definido.

Functor:

https://gist.github.com/thiagomg/f79848f06a939b7fa4b7

Lambda:

https://gist.github.com/thiagomg/abc49253fd507d575647

Note que a referência da variável b será passado junto com a função lambda.

Como funciona a inferência feita em um lambda?


Agora, vamos focar somente no lambda.
O que está sendo inferido?

1. Parâmetro v
2. Retorno, se tem o qual é
3. O tipo do lambda baseado em std::function

https://gist.github.com/thiagomg/033f1a7d68f234343f0c

1. Parâmetro v
2. Retorno: resultado do operador * dos tipos de v e b
3. O tipo do lambda baseado em std::function

https://gist.github.com/thiagomg/52a2cf48ed44739fd81d

1. O tipo do lambda, sendo std::function<int(int)>

https://gist.github.com/thiagomg/4259b8b6fc7074025b14

Lista de captura de um lambda


O lambda tem alguns tipos de captura:
[a] -> captura a variável a por valor
[=] -> captura todas as variáveis por valor
[&a] -> captura a variável a por referência
[&] -> captura todas as variáveis por referência
[a, &b] -> captura a por valor e b por referência
[] -> não captura nada

Legibilidade interessante


E veja se não fica muito boa a legibilidade.

https://gist.github.com/thiagomg/0d15b70d53aa72ecdbc0

Se esses códigos fossem mostrados para um programador C++ de uns 10 anos atrás, ele certamente não acreditaria que é a mesma linguagem!

Fonte:
https://github.com/SimplyCpp/examples/blob/master/lambda.cpp
https://github.com/SimplyCpp/examples/blob/master/lambda2.cpp

Comentários

Postagens mais visitadas deste blog

Mestre Iota

Iota é a nona letra do alfabeto grego, ela é equivalente à letra i do nosso alfabeto. Por convenção ou hábito, utilizamos a letra i na programação para indicar algum tipo de incrementador, como por exemplo, em um for-loop . https://gist.github.com/fabiogaluppo/a23894ae743f7dd29274 Curiosamente, iota , como identificador, também é utilizado na programação para indicar uma sequência finita e consecutiva de números inteiros, como por exemplo, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]. Inclusive, originalmente na STL existia a função iota , inspirada pela linguagem de programação APL , você pode conferir neste link: http://www.sgi.com/tech/stl/iota.html

Valores Aleatórios Simplificados

A partir do C++ 11, foi introduzido o header <random>  com diversos facilitadores para suporte de geração de números aleatórios. A produção destes números é feita através da combinação de duas categorias de objetos: os geradores e os distribuidores. Os geradores, são responsáveis pela geração dos números, e os distribuidores são responsáveis pela transformação dos números gerados em algum tipo de distribuição de probabilidade.  Como por exemplo, uma distribuição normal (aquela da Gaussiana) ou uma distribuição de Pareto (aquela do 80-20). As opções não faltam, como você pode ver nas referências, por exemplo:   http://www.cplusplus.com/reference/random/ ou  http://en.cppreference.com/w/cpp/header/random .

Policy-based design: log writer

Policy-based design Vamos neste artigo dar mais uma pincelada no Policy-based design . Vamos fazer como exemplo uma classe de log. Como este é só um exemplo, não vamos considerar múltiplos parâmetros no log, mas somente uma string, assim não fugiremos do assunto. Uma das coisas mais importantes neste tipo de design é o desacoplamento. Ele é uma excelente alternativa ao uso de interfaces por duas razões: Não gera chamadas virtuais (ou um nível de indireção em tempo de execução) Duck typing ( https://pt.wikipedia.org/wiki/Duck_typing ) Eu gosto bastante desse tipo de design, já usado aqui: http://simplycpp.com/2016/02/05/leitura-de-configuracao-em-c/