Introdução
A Programação Funcional tem raízes no cálculo lambda, formalizado pelo matemático Alonzo Church nos anos 1930, décadas antes da existência de computadores modernos. Sua primeira grande expressão em linguagem de programação foi o Lisp (1958), e o paradigma ganhou força prática com linguagens como Haskell, Erlang, F# e, mais recentemente, com a incorporação de recursos funcionais em linguagens multiparadigma como JavaScript, C# e Python.
Princípios centrais
- Funções puras — dado o mesmo input, uma função pura sempre retorna o mesmo output, sem produzir efeitos colaterais (não altera variáveis externas, não grava em disco, não modifica o argumento recebido).
- Imutabilidade — os dados não são alterados após criados; em vez de modificar uma estrutura existente, cria-se uma nova versão com a alteração aplicada.
- Funções de primeira classe / funções de alta ordem — funções podem ser tratadas como qualquer outro valor: armazenadas em variáveis, passadas como argumento e retornadas por outras funções.
-
Composição de funções — programas são construídos combinando funções pequenas em pipelines (
map,filter,reducesão os exemplos mais comuns no dia a dia). -
Recursão no lugar de laços mutáveis, já que, sem estado mutável,
for/whiletradicionais perdem o sentido em sua forma pura.
Como não há estado compartilhado sendo alterado por múltiplas partes do código, o raciocínio sobre o comportamento do programa fica mais previsível — e a paralelização se torna muito mais segura, já que não existe o risco clássico de condições de corrida sobre uma mesma variável mutável.
Exemplo
// Exemplo de Programação Funcional em TypeScript
type Produto = { nome: string; preco: number };
const produtos: Produto[] = [
{ nome: "Notebook", preco: 3000 },
{ nome: "Mouse", preco: 50 },
{ nome: "Teclado", preco: 150 },
];
// Função de alta ordem que retorna outra função (currying)
const aplicarDesconto = (percentual: number) => (preco: number) =>
preco * (1 - percentual);
const aplicarDesconto10 = aplicarDesconto(0.10);
// Composição via map + reduce, sem alterar "produtos"
const totalComDesconto = produtos
.map(p => aplicarDesconto10(p.preco))
.reduce((acumulado, precoAtual) => acumulado + precoAtual, 0);
console.log(totalComDesconto); // produtos original permanece intacto
Repare que produtos nunca é modificado — map gera um novo array, e reduce agrega esse novo array em um único valor. Essa é a essência da imutabilidade e da ausência de efeitos colaterais.
Vantagens e limitações
- Vantagens: previsibilidade, testabilidade (funções puras são triviais de testar — mesmo input, mesmo output, sem mocks de estado), facilidade de paralelização/concorrência.
- Limitações: pode ter uma curva de aprendizado mais alta para quem vem de um background imperativo; nem todo domínio de problema se encaixa naturalmente em transformações de dados (por exemplo, interações com I/O e efeitos colaterais são inevitáveis em algum ponto — a maioria das linguagens funcionais lida com isso através de abstrações específicas, como Monads em Haskell).
Top comments (0)