Dominando Currying e Partial Application em JavaScript em Projetos Reais Já leu

Currying: A Arte de Transformar Funções Currying é uma técnica que transforma uma função que aceita múltiplos argumentos em uma sequência de funções que aceitam um argumento por vez. Quando você "currifica" uma função, cada chamada retorna uma nova função que espera pelo próximo argumento até que todos sejam fornecidos. A vantagem real aparece quando você precisa reutilizar a função parcialmente. Currying permite que você crie versões especializadas sem duplicar código. Isso torna seu código mais modular e fácil de testar. Implementando um Curryificador Universal Criar um auxiliar que transforma qualquer função em sua versão currificada é essencial na prática. Aqui está uma implementação robusta: Este padrão é poderoso porque permite flexibilidade: você pode chamar com um argumento ou vários de uma vez, e ainda assim obtém o resultado correto quando todos forem fornecidos. Partial Application: Fixando Argumentos Estrategicamente Enquanto currying força uma abordagem de um argumento por vez, partial application é mais pragmática: você fixa alguns argumentos e deixa

Currying: A Arte de Transformar Funções

Currying é uma técnica que transforma uma função que aceita múltiplos argumentos em uma sequência de funções que aceitam um argumento por vez. Quando você "currifica" uma função, cada chamada retorna uma nova função que espera pelo próximo argumento até que todos sejam fornecidos.

// Função normal
function somar(a, b, c) {
  return a + b + c;
}

// Função currificada
function somarCurrificada(a) {
  return function(b) {
    return function(c) {
      return a + b + c;
    };
  };
}

console.log(somarCurrificada(1)(2)(3)); // 6

A vantagem real aparece quando você precisa reutilizar a função parcialmente. Currying permite que você crie versões especializadas sem duplicar código. Isso torna seu código mais modular e fácil de testar.

Implementando um Curryificador Universal

Criar um auxiliar que transforma qualquer função em sua versão currificada é essencial na prática. Aqui está uma implementação robusta:

function curry(fn) {
  const arity = fn.length; // número de parâmetros esperados

  return function curried(...args) {
    if (args.length >= arity) {
      return fn(...args);
    }
    return (...nextArgs) => curried(...args, ...nextArgs);
  };
}

// Testando com uma função real
const multiplicar = (a, b, c) => a * b * c;
const multiplicarCurrificada = curry(multiplicar);

console.log(multiplicarCurrificada(2)(3)(4));        // 24
console.log(multiplicarCurrificada(2, 3)(4));        // 24
console.log(multiplicarCurrificada(2)(3, 4));        // 24

Este padrão é poderoso porque permite flexibilidade: você pode chamar com um argumento ou vários de uma vez, e ainda assim obtém o resultado correto quando todos forem fornecidos.

Partial Application: Fixando Argumentos Estrategicamente

Enquanto currying força uma abordagem de um argumento por vez, partial application é mais pragmática: você fixa alguns argumentos e deixa outros para depois. Não é tudo ou nada, mas uma especialização estratégica.

// Partial application manual
function dividir(a, b) {
  return a / b;
}

// Fixar o divisor como 2
function dividirPorDois(a) {
  return dividir(a, 2);
}

console.log(dividirPorDois(10)); // 5

// Usando bind (nativo do JavaScript)
const dividirPorTres = dividir.bind(null, 30);
console.log(dividirPorTres(2)); // 15 (30 / 2)

A diferença sutil mas importante: currying retorna sempre uma função até ter todos os argumentos; partial application retorna o resultado assim que houver argumentos suficientes para executar.

Criando um Helper de Partial Application

Para maior controle e legibilidade, implemente um utilitário dedicado:

function partial(fn, ...fixedArgs) {
  return function(...restArgs) {
    return fn(...fixedArgs, ...restArgs);
  };
}

// Aplicação prática
const lerquivo = (encoding, filePath) => `Lendo ${filePath} com encoding ${encoding}`;

const lerUTF8 = partial(lerquivo, 'utf-8');
const lerLatin1 = partial(lerquivo, 'latin1');

console.log(lerUTF8('/arquivo.txt'));        // Lendo /arquivo.txt com encoding utf-8
console.log(lerLatin1('/arquivo.txt'));      // Lendo /arquivo.txt com encoding latin1

Partial application é especialmente útil em composição de funções e callbacks, onde você precisa adaptar uma função existente sem reescrevê-la completamente.

Casos de Uso Reais no Dia a Dia

Na prática, essas técnicas resolvem problemas concretos. Considere um cenário comum: processar dados com funções especializadas.

// Exemplo: Processador de eventos com currying
const registrarLog = curry((nivel, modulo, mensagem) => {
  console.log(`[${nivel}] [${modulo}] ${mensagem}`);
});

const logErro = registrarLog('ERRO');
const logErroAuth = logErro('AUTH');
const logErroDatabase = logErro('DATABASE');

logErroAuth('Falha na autenticação');      // [ERRO] [AUTH] Falha na autenticação
logErroDatabase('Conexão perdida');        // [ERRO] [DATABASE] Conexão perdida

// Exemplo: Validação com partial application
const validarEmail = (pattern, valor) => pattern.test(valor);
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

const validarEmailPadrao = partial(validarEmail, emailRegex);
console.log(validarEmailPadrao('user@example.com')); // true
console.log(validarEmailPadrao('invalid-email'));    // false

Esses padrões simplificam a criação de pipelines de transformação de dados, frameworks que precisam de callbacks customizados, e sistemas que lidam com configurações variáveis. Eles reduzem repetição de código e aumentam a reutilização.

Conclusão

Currying e partial application são ferramentas poderosas da programação funcional que transformam como você escreve JavaScript. Primeiro ponto: currying força uma disciplina de um argumento por vez, resultando em funções altamente reutilizáveis e componíveis. Segundo ponto: partial application oferece flexibilidade pragmática, permitindo especializar funções sem a rigidez do currying. Terceiro ponto: ambas reduzem duplicação de código e facilitam testes, sendo especialmente valiosas em arquiteturas que usam composition e higher-order functions.

Domine essas técnicas e você terá um código mais limpo, testável e verdadeiramente funcional.

Referências


Artigos relacionados