Um exemplo da vida real do uso da função curry? [fechadas]

8

Eu estava com dificuldades para encontrar um exemplo da vida real do uso da função curry e obter o benefício de usar o curry.

Quando eu google função curry, muitas vezes vejo o exemplo como

let add = x => y => x + y;
let add10 = add(10);
console.log(add10(20));

Devo dizer que realmente não vejo o valor de usar curry neste exemplo.

Depois de ler as respostas neste SO /programming/113780/javascript-curry-what-are-the-practical-applications , ainda não vejo o benefício de usá-lo.

Por exemplo, a resposta com a pontuação mais alta fornece um exemplo de conversor, mas esse exemplo pode ser reescrito sem curry, como mostra outra resposta.

Eu também li as respostas Qual é a vantagem de currying? (embora a discussão não se limite ao javascript), ainda sinto que a versão curry pode ser reescrita sem curry (em js).

Então, alguém pode me mostrar a vantagem / benefício "real" do uso de curry em javascript?

---- atualização ----

Exceto pelas respostas que recebi, também acho que o exemplo de log mostra o benefício de usá-lo.

Qiulang
fonte
2
Concordo que a maioria dos exemplos básicos de curry que você encontra on-line são extremamente inexpressivos.
user949300
@ user949300 BTW, eu realmente não entendo por que minha pergunta foi votada. Não é uma pergunta "válida" quando você pensa em js curry? Eu tenho medo que ele seja fechado no SO, então eu perguntei aqui. :(
Qiulang
Eu achei o currying muito útil quando uma função lib externa espera uma função (por exemplo, retorno de chamada) que recebe um número determinado de argumentos e você tem uma função (por exemplo, manipulador) que recebe mais argumentos, mas você deseja passar valores constantes para esses argumentos adicionais. Cópia parcial é, em seguida, mais legível do que fazer uma função de seta
tutuDajuju
3
"Ainda sinto que a versão curry pode ser reescrita sem curry" - Isso é trivial, já que é disso que se trata o curry. O ponto principal da currying é a observação de que qualquer função de n parâmetros pode ser reescrita como uma função de n-1 parâmetros que retornam uma função que aceita o enésimo parâmetro. Observe também que esta afirmação se aplica a praticamente tudo. Cada forloop pode ser reescrito como um whileloop. Cada ifdeclaração pode ser reescrita como um whileloop. Cada whileloop pode ser reescrito como um goto. Isso não significa que eles não são úteis.
Jörg W Mittag

Respostas:

8

Eu quase nunca usei o Currying, mas aqui está um exemplo recente em que isso se mostrou útil. Eu estava codificando para o jogo Battlesnake , mas isso se aplica a muitos jogos. Eles fornecem várias matrizes, fornecendo a localização de sua cobra, cobras inimigas e comida. Digamos que você esteja considerando mudar para um determinado ponto {x, y} e deseje verificar se ele contém outra cobra, comida ou até você. A primeira passagem seria escrever um código como este (usarei uma mistura de funções e novas setas com fangled)

// utility function
function samePoint(p1, p2) {
  return (p1.x === p2.x) && (p1.y === p2.y);
}

e em algum lugar no código ir

let possibleMove = {x,y}; // where you are thinking of moving
...
if (foodArray.some((p) => samePoint(p, possibleMove )) {
  // this move looks tasty, give it a bonus value...
}

Não é ruim, mas, como você fará isso em muitos lugares do seu código, um pouco entediante e desajeitado. E, pela minha experiência, é fácil atrapalhar os dois argumentos. :-( O problema subjacente é que some()(ou find()) aceita uma função usando apenas um único argumento, e você realmente precisa de dois argumentos , os dois pontos. Então, você pensa em currying! Aqui muitos usariam setas, acho as funções aninhadas mais claras:

function samePointAs(p1) {
  return function(p2) {
    return samePoint(p1, p2);
  }
}

Então, seu teste "é essa comida" se torna

let possibleMove = {x,y}; // where you are thinking of moving
...
if (foodArray.some(samePointAs(possibleMove )) {
  // this move looks tasty, give it a bonus value...
}

Isso vai fazer de você um milionário da Internet? Provavelmente não. Mas isso simplifica e, nesse caso, esclarece seu código.

user949300
fonte
Olá, eu gosto do seu exemplo, por isso marquei sua resposta como a resposta aceita. Obrigado.
Qiulang
Olá, minha pergunta é colocada em espera. Até conseguiu um voto de exclusão. Eu estava tentando editá-lo para torná-lo adiado sem sucesso. Eu queria saber, você pode me ajudar a editá-lo?
Qiulang
14

Curry no seu exemplo realmente não faz sentido, eu concordo. Para ver a funcionalidade do curry, é necessário combiná-lo com funções de ordem superior: funções que assumem outras funções como parâmetro.

O exemplo mais típico disso é mapear, filtrar e reduzir, embora outra situação comum seja retornos de chamada. Ao aplicar parcialmente uma função, você pode passar a função parcialmente aplicada a essas funções de ordem superior. O curry faz sentido quando na maioria das vezes você deseja usar uma função é para um aplicativo parcial, para que possa ser passado para outra função de ordem superior.

Um exemplo mais ilustrativo pode parecer assim:

let array1 = [1, 4, 9, 16];
let add = x => y => x + y;
array2 = array1.map(foo ? add(10) : add(20));

O curry nunca é necessário, sim, pois você sempre pode criar uma função anônima / flecha a partir de uma função regular quando precisar, mas em algumas situações pode ser muito conveniente ter a função curry comparada à regular (e em outras situações, é apenas tornando as coisas chatas e lentas).

Lie Ryan
fonte
2
"mas em algumas situações, pode ser muito conveniente ter uma função ao curry comparada à regular", então você pode dar um exemplo disso? Obrigado!
Qiulang
@Qiulang Um exemplo é se você tem uma série de lógicas de configuração que controlam como chamar uma função que possui muitos parâmetros. Se você não possui uma função ao curry, geralmente precisará criar um objeto com uma API fluente ou fornecer algum tipo de método clone_and_update () ou criar uma classe Builder separada para criar o parâmetro da função incrementalmente. Um exemplo típico disso é o construtor de consultas do ORM. Com a função ao curry, você pode simplesmente chamar a função normalmente em cada etapa.
Lie Ryan
@LieRyan No JavaScript , onde é tão trivial criar uma opção "objeto" usando {}, não achei as classes Builder muito úteis ou comuns. Você pode citar alguns exemplos?
user949300
1
@ user949300 A criação de vinte objetos com dez membros que diferem apenas por um ou dois parâmetros não é mais fácil em JS do que em outros idiomas. Com o objeto construtor imutável que usa interface fluente, você pode construir o objeto de configuração base e simplesmente se ramificar para criar conjuntos de argumentos diferentes. Esse tipo de padrão geralmente pode parecer muito pesado no código do aplicativo, mas é bastante comum para os autores de bibliotecas / estruturas.
Lie Ryan
1
Aponte o argumento, mas @LieRyan com o newfangled Object.assign()é muito fácil ramificar-se de uma configuração básica.
user949300