Funcao Composta - Exercícios De Função Composta - FDPLEARN
Exercícios De Função Composta - FDPLEARN

O que acontece quando você encadeia funções na prática

Eu aprendi sobre composição de funções na universidade e achava que era só substituir variáveis em cadeia. Dois anos depois, passando o primeiro ano como desenvolvedor fullstack, eu precisei montar um pipeline de transformação de dados que ia buscar um payload bruto na API, parsear o JSON, normalizar os campos, aplicar regras de negócio e formatar a resposta final. Eu tentava fazer tudo em um único bloco de código. Funcionou por três semanas. Depois alguém mudou um campo na API e tudo quebrou de um jeito que eu não conseguia rastrear. Aí eu parei e pensei: isso aqui é exatamente o que composition é pra resolver, só que eu estava escrevendo como se fosse um script único. A composição de funções, ou funcao composta, no fundo, é a operação de encadear duas ou mais funções de modo que a saída de uma vire a entrada da próxima. Não tem mistério nisso. O conceito existe desde a matemática formal — você tem f(x) e g(x), então (f g)(x) = f(g(x)). Mas a parte que ninguém ensina direito é que, no código do dia a dia, a ordem importa e isso gera confusão constante. A leitura vai da direita para a esquerda: primeiro você aplica g, depois f. Muitos desenvolvedores, eu incluso, escrevem na ordem inversa mentalmente e acabam invertendo o fluxo sem perceber.

Entendendo funcao composta com exemplos reais

Vou mostrar com JavaScript porque é a linguagem que eu mais uso, mas o conceito é transversal a qualquer ambiente funcional. Suponha que você tenha uma lista de strings representando números e precisa transformá-las em números inteiros, depois dobrar cada valor e, por fim, filtrar apenas os pares maiores que 10. A abordagem ingênua seria um loop for dentro de um map dentro de um filter. Funciona. É legível o suficiente. O problema aparece quando você precisa testar cada etapa isoladamente. O loop encadeado não dá essa possibilidade. Com composição, você divide cada transformação em uma função pura e depois as encadeia.

Por exemplo: const stringParaNumero = str => parseInt(str, 10);

const dobrar = n => n * 2; const maiorQueDez = n => n > 10;

const filtrarPares = n => n % 2 === 0; Depois você monta o pipeline. Em JavaScript moderno, usando o operador Pipe doTC39 ou uma biblioteca como RxJS ou uma implementation simples de compose:

const pipeline = compose(   map(filtrarPares),

👉 Clique no botão abaixo para saber mais sobre o assunto!

  map(maiorQueDez),   map(dobrar),

  map(stringParaNumero), );

O resultado é uma função única que recebe um array de strings e retorna um array de números transformados e filtrados. Cada etapa é testável de forma independente. Isso resolve um problema que parecia menor: a capacidade de escrever testes unitários para cada transformação sem precisar montar todo o contexto de dados só pra verificar se a função dobrar está funcionando.

Como montar uma composição que não quebra em produção

Existe um detalhe que eu descobri do jeito difícil. Tipagem implícita. Quando você compõe funções sem tipagem explícita, a saída da função anterior pode assumir um formato ligeiramente diferente do que a próxima função espera. No meu caso, a função stringParaNumero retornava NaN quando o input vinha vazio. O filter seguinte simplesmente ignorava NaN por acidente, mas em outro contexto, NaN teria propagado silenciosamente pelo pipeline e causado um erro só horas depois, em uma tela de relatório que ninguém monitorava. A solução que eu adotei foi criar um wrapper de validação antes da composição. Não é elegante, mas é honesto. Eu nunca mais vi aquele bug aparecer.

Outro ponto que merece atenção é a ordem de aplicação. No JavaScript, a função compose aplica da direita para a esquerda. Em linguagens como Elm ou PureScript, o operador de composição segue convenções diferentes. Se você estiver migrando de uma linguagem para outra, a leitura muda e isso custa tempo de debug. Eu perdi meio dia num projeto porque assumi que compose em TypeScript se comportava igual ao compose em JavaScript, e não se comportava exatamente da mesma forma com generics. Quando lidar com funcao composta, considere também o custo de performance em pipelines longos. Cada função adicional adiciona uma chamada de stack. Em JavaScript isso é irrelevante para a maioria dos casos, mas em sistemas onde você processa milhões de registros por segundo, o overhead de múltiplas chamadas de função pode somar. Nesse cenário, unificar algumas etapas em uma única função costuma ser mais eficiente do que manter uma composição puramente modular. É um trade-off real entre manutenibilidade e throughput, e você precisa decidir qual dos dois pesa mais no seu contexto específico.

Quando a composição não é a resposta certa

Eu já vi times inteiros tentarem transformar lógica condicional complexa em composição de funções. Isso não funciona bem. Composição brilha quando você tem transformações lineares, puras, sem efeitos colaterais. Se sua lógica envolve decisões ramificadas, chamadas de API, escrita em banco de dados, ou estados mutáveis, forçar composição só vai tornar o código mais difícil de ler do que uma simples sequência de instruções. A composição também não lida bem com funções que podem falhar e retornar diferentes tipos. Sem um sistema de tipo robusto, como o que o TypeScript oferece, uma função na cadeia que retorne null inesperadamente vai propagar esse null pela pipeline inteira e o erro só vai ser percebido quando o resultado final for usado. Nesse caso, um monad Either ou Option é uma alternativa mais segura do que simplesmente encadear funções.

O ponto principal é: composição de funções é uma ferramenta, não uma filosofia. Use quando o problema se encaixa. Não use quando o problema pede uma estrutura diferente. A maior parte dos bugs que eu já vi em produção relacionados a composição vieram de pessoas tentando encaixar algo que não era linear numa composição linear.