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.