Programação Funcional em C++: Nível Avançado

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Programação Funcional em C++: Nível Avançado



Programação Funcional (PF) é um paradigma onde os cálculos são representados como avaliação de funções matemáticas, evitando mudanças de estado e dados mutáveis. Embora C++ tenha sido originalmente uma linguagem orientada a objetos e procedural, a partir do padrão C++11 ele ganhou ferramentas poderosas para PF: expressões lambda, std::function, std::bind, e em C++17 foi adicionado suporte para std::optional e std::variant, que permitem implementar padrões monádicos. Neste artigo, exploraremos técnicas avançadas de programação funcional em C++: composição de funções, currying, trabalho com mônadas e criação de funções puras usando recursos modernos da linguagem.



1. Expressões Lambda e Funções Puras



Expressões lambda são a base do estilo funcional em C++. Elas permitem criar funções anônimas no local, ideais para algoritmos de <algorithm>. No entanto, para uma verdadeira PF, é importante que as lambdas sejam puras — ou seja, não tenham efeitos colaterais e não dependam de estado mutável externo.



#include <iostream>#include <vector>#include <algorithm>

int main() { std::vector<int> numbers = {1, 2, 3, 4, 5};

// Lambda pura: apenas dados de entrada, apenas saída auto square = [](int x) { return x * x; };

// Aplicando transform sem efeitos colaterais std::vector<int> squared; std::transform(numbers.begin(), numbers.end(), std::back_inserter(squared), square);

for (int n : squared) std::cout << n << " "; // 1 4 9 16 25 return 0;}


Para uso avançado, evite captura por referência ([&]) se não for crítico. Captura por valor ([=]) ou enumeração explícita de capturas torna a lambda mais previsível e testável.



2. Composição de Funções com std::function e Operadores



Composição é a combinação de duas ou mais funções em uma. Em C++, é possível implementar composição usando templates e std::function. Vejamos um compositor genérico:



#include <functional>#include <iostream>

template <typename F, typename G>auto compose(F f, G g) { return [f, g](auto x) { return f(g(x)); };}

int main() { auto addOne = [](int x) { return x + 1; }; auto multiplyByTwo = [](int x) { return x * 2; };

auto addThenMultiply = compose(multiplyByTwo, addOne); std::cout << addThenMultiply(5) << std::endl; // (5+1)*2 = 12

// Composição de múltiplas funções auto triple = compose(multiplyByTwo, compose(addOne, addOne)); std::cout << triple(5) << std::endl; // ((5+1)+1)*2 = 14 return 0;}


Para cadeias mais complexas, pode-se usar um operador de pipeline (semelhante a |> em outras linguagens). Em C++20, é possível sobrecarregar operator| para criar uma sintaxe conveniente:



#include <functional>#include <iostream>

template <typename F>class Pipeable { F f;public: Pipeable(F func) : f(func) {} template <typename T> auto operator()(T x) const { return f(x); }};

template <typename T, typename F>auto operator|(T x, Pipeable<F> p) { return p(x);}

int main() { auto addOne = Pipeable([](int x) { return x + 1; }); auto square = Pipeable([](int x) { return x * x; });

int result = 5 | addOne | square; // (5+1)^2 = 36 std::cout << result << std::endl; return 0;}


Essa abordagem torna o código declarativo e fácil de ler.



3. Currying e Aplicação Parcial



Currying é a transformação de uma função de vários argumentos em

Blogs

Book Recommendations