Esse recurso da linguagem JavaScript pode ajudar a organizar seu código e proporcionar uma nova compreensão de como as funções funcionam.
As funções Curried podem ajudar a tornar seu código JavaScript mais legível e expressivo. A técnica currying é ideal quando você deseja dividir lógica complexa em pedaços de código menores, independentes e mais gerenciáveis.
Aprenda tudo sobre funções curry em JavaScript, como usar a técnica de função curry para criar funções parcialmente aplicadas, bem como casos de uso da vida real para funções curried e parcialmente aplicadas funções.
O que é curry?
Currying recebeu o nome do matemático Haskell B. Curry, e o conceito deriva do cálculo Lambda. Currying pega uma função que recebe mais de um parâmetro e a divide em uma série de funções unárias (um parâmetro). Em outras palavras, uma função curried aceita apenas um parâmetro por vez.
Um exemplo básico de curry
Abaixo está um exemplo de função curry:
functionbuildSandwich(ingredient1) {
return(ingredient2) => {
return(ingredient3) => {
return`${ingredient1},${ingredient2},${ingredient3}`
}
}
}
O construirSandwich() função retorna outra função - uma função anônima que recebe o ingrediente2 argumento. Então, esta função anônima retorna outra função anônima que recebe ingrediente3. Finalmente, esta última função retorna o literal do template, uma forma de formatando strings em JavaScript.
O que você criou é uma função aninhada onde cada função chama aquela que está abaixo dela até chegarmos ao fim. Agora, quando você ligar construirSandwich() e passar um único parâmetro, ele retornará a parte da função cujos argumentos você ainda não forneceu:
console.log(buildSandwich("Bacon"))
Você pode ver na saída que buildSandwich retorna uma função:
Para completar a chamada de função, você precisaria fornecer todos os três argumentos:
buildSandwich("Bacon")("Lettuce")("Tomato")
Este código passa “Bacon” para a primeira função, “Alface” para a segunda e “Tomate” para a última função. Em outras palavras, o construirSandwich() A função é realmente dividida em três funções, com cada função recebendo apenas um parâmetro.
Embora seja perfeitamente válido fazer curry usando as funções tradicionais, todo o aninhamento pode ficar bem feio à medida que você se aprofunda. Para contornar isso, você pode usar funções de seta e aproveitar sua sintaxe mais limpa:
const buildMeal = ingred1 =>ingred2 =>ingred3 =>
`${ingred1}, ${ingred2}. ${ingred3}`;
Esta versão refatorada é mais concisa, uma vantagem de usar funções de seta vs funções regulares. Você pode chamar a função da mesma forma que fez com a anterior:
buildMeal("Bacon")("Lettuce")("Tomato")
Funções de Curry Parcialmente Aplicadas
Funções parcialmente aplicadas são um uso comum do currying. Esta técnica envolve fornecer apenas os argumentos necessários de cada vez (em vez de fornecer todos os argumentos). Sempre que você invoca uma função passando todos os parâmetros necessários, você diz que “aplicou” aquela função.
Vejamos um exemplo:
const multiply = (x, y) => x * y;
Abaixo está a versão com curry de multiplicar:
const curriedMultiply = x =>y => x * y;
O curryMultiply() função recebe o x argumento para a primeira função e sim para a segunda função, então multiplica ambos os valores.
Para criar a primeira função parcialmente aplicada, chame curryMultiple() com o primeiro parâmetro e atribua a função retornada a uma variável:
const timesTen = curriedMultiply(10)
Neste ponto, o código "aplicou parcialmente" o curryMultiply() função. Então, sempre que você quiser ligar vezesDez(), você só precisa passar um número e o número será automaticamente multiplicado por 10 (que é armazenado dentro da função aplicada):
console.log(timesTen(8)) // 80
Isso permite que você desenvolva uma única função complexa criando diversas funções personalizadas a partir dela, cada uma com sua própria funcionalidade bloqueada.
Dê uma olhada em um exemplo que está mais próximo de um caso de uso real de desenvolvimento web. Abaixo você tem um atualizarElemText() função que recebe um elemento eu ia na primeira chamada, o conteúdo na segunda chamada e, em seguida, atualiza o elemento com base no eu ia e conteúdo que você forneceu:
const updateElemText = id = content
=> document.querySelector(`#${id}`).textContent = content// Lock the element's id into the function:
const updateHeaderText = updateElemText('header')
// Update the header text
updateHeaderText("Hello World!")
Composição de funções com funções curry
Outro uso comum do curry é a composição de funções. Isso permite chamar funções pequenas, em uma ordem específica, e combiná-las em uma função única e mais complexa.
Por exemplo, em um hipotético site de comércio eletrônico, aqui estão três funções que você pode querer executar uma após a outra (em ordem precisa):
const addCustomer = fn =>(...args) => {
console.log("Saving customer info")
return fn(...args)
}const processOrder = fn =>(...args) => {
console.log(`processing order #${args[0]}`)
return fn(...args);
}
let completeOrder = (...args) => {
console.log(`Order #${[...args].toString()} completed.`);
}
Observe que este código usa o deixar palavra-chave para definir o ordem completa() função. Isso permite reatribuir um valor à variável e faz parte do como funciona o escopo em JavaScript.
Em seguida, você precisa chamar as funções na ordem inversa (de dentro para fora), porque você deseja adicionar os clientes primeiro:
completeOrder = (processOrder(completeOrder));
completeOrder = (addCustomer(completeOrder));
completeOrder("1000")
Isso lhe dará a seguinte saída:
Se você escrevesse as funções acima da maneira normal, o código seria mais ou menos assim:
functionaddCustomer(...args) {
returnfunctionprocessOrder(...args) {
returnfunctioncompleteOrder(...args) {
// end
}
}
}
Quando você liga para o adicionarCliente() função e passar os argumentos, você está começando de dentro e trabalhando até o topo da função.
Converter uma função normal em uma função curry com uma função curry
Se você planeja usar muito as funções curried, pode agilizar o processo com uma função auxiliar.
Esta função converterá qualquer função normal em uma função curry. Ele usa recursão para lidar com qualquer número de argumentos.
const curry = (fn) => {
return curried = (...args) => {
if (fn.length !== args.length) {
return curried.bind(null, ...args)
}
return fn(...args);
}
}
Esta função aceitará qualquer função escrita padrão que receba mais de um parâmetro, retornando uma versão curried dessa função. Para ver isso em ação, use este exemplo de função que pega três parâmetros e os adiciona:
const total = (x, y, z) => x + y + z
Para converter esta função, chame o Curry() função e passe total como argumento:
const curriedTotal = curry(total)
Agora, para chamar a função, basta passar todos os argumentos:
console.log(curriedTotal(10)(20)(30)) // 60
Mais sobre funções em JavaScript
As funções do JavaScript são extremamente flexíveis e as funções currying são apenas uma pequena parte disso. Existem muitos outros tipos de funções, como funções de seta, funções construtoras e funções anônimas. Familiarizar-se com essas funções e seus componentes é fundamental para dominar o JavaScript.