¿Un ejemplo de la vida real del uso de la función de curry? [cerrado]

8

Me costó encontrar un ejemplo de la vida real del uso de la función de curry y obtener el beneficio de usar curry.

Cuando busco en Google la función de curry, a menudo veo el ejemplo como

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

Tengo que decir que realmente no veo el valor de usar curry en este ejemplo.

Después de leer las respuestas en este SO /programming/113780/javascript-curry-what-are-the-practical-applications , todavía no veo el beneficio de usarlo.

Por ejemplo, la respuesta con la puntuación más alta da un ejemplo de convertidor, pero ese ejemplo puede reescribirse sin curry como muestra otra respuesta.

También leí las respuestas ¿Cuál es la ventaja de curry? (aunque la discusión no se limita a JavaScript) Todavía tengo la sensación de que la versión de curry se puede reescribir sin curry (en js).

Entonces, ¿alguien puede mostrarme la ventaja / beneficio "real" de usar curry en javascript?

---- actualización ----

Excepto por las respuestas que obtuve, también encuentro que el ejemplo de registro aquí muestra el beneficio de usarlo.

Qiulang
fuente
2
Estoy de acuerdo en que la mayoría de los ejemplos básicos de curry que encuentras en línea son extremadamente poco impresionantes.
user949300
@ user949300 BTW, realmente no entiendo por qué mi pregunta fue rechazada. ¿No es una pregunta "válida" cuando piensas en js curry? Me preocupa que se cierre en SO, así que pregunté aquí. :(
Qiulang
Encontré que el curry es más útil cuando una función lib externa espera una función (por ejemplo, devolución de llamada) que toma un número dado de argumentos y tiene una función (por ejemplo, controlador) que toma más argumentos, pero desea pasar valores constantes para estos argumentos adicionales. La copia parcial es más legible que hacer que una flecha funcione
tutuDajuju
3
"Todavía tengo la sensación de que la versión de curry se puede reescribir sin curry". Esto es algo trivial, ya que de eso se trata el curry. El punto central del curry es la observación de que cualquier función de n parámetros puede reescribirse como una función de n-1 parámetros que devuelve una función que toma el enésimo parámetro. También tenga en cuenta que esta afirmación es cierta para casi todo. Cada forciclo puede reescribirse como un whileciclo. Cada ifdeclaración puede reescribirse como un whilebucle. Cada whilebucle se puede reescribir como a goto. Eso no significa que no sean útiles.
Jörg W Mittag

Respuestas:

8

Casi nunca he usado Curry, pero aquí hay un ejemplo reciente donde demostró ser útil. Estaba codificando el juego Battlesnake , pero esto se aplicaría a muchos juegos. Le proporcionan varios arreglos, que le dan la ubicación de su serpiente, serpientes enemigas y comida. Supongamos que está considerando mudarse a un cierto punto {x, y}, y desea verificar si contiene otra serpiente, comida o incluso usted mismo. El primer paso sería escribir código como este (usaré una combinación de funciones y nuevas flechas)

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

y en algún lugar del 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...
}

No está mal, pero, dado que harás esto en muchos lugares en tu código, es un poco tedioso y torpe. Y, desde mi experiencia, es fácil confundir los dos argumentos. :-( El problema de fondo es que la some()(o find()) aceptar una función de tomar solamente un único argumento, y que realmente necesita dos argumentos , los dos puntos lo tanto, se piensa en currificación Aquí muchos podrían utilizar flechas, encuentro funciones anidadas más clara.!:

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

Entonces, su prueba de "es ese alimento" se convierte

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

¿Esto te hará millonario en Internet? Probablemente no. Pero sí simplifica y, en este caso, aclara su código.

user949300
fuente
Hola, me gusta tu ejemplo, así que marqué tu respuesta como la respuesta aceptada. Gracias.
Qiulang
Hola, mi pregunta queda en espera. Incluso obtuvo un voto de eliminación. Estaba tratando de editarlo para que se suspendiera sin resultado. Me preguntaba ¿puedes ayudarme a editarlo?
Qiulang
14

Curry en su ejemplo realmente no tiene sentido, estoy de acuerdo. Para ver la funcionalidad del curry, debe combinarlo con funciones de orden superior: funciones que toman otras funciones como parámetro.

El ejemplo más típico de esto es mapear, filtrar y reducir, aunque otra situación común son las devoluciones de llamada. Cuando aplica parcialmente una función, puede pasar la función parcialmente aplicada a estas funciones de orden superior. El curry tiene sentido cuando la mayoría de las veces que desee utilizar una función es para una aplicación parcial, de modo que pueda pasar a otra función de orden superior.

Un ejemplo más ilustrativo podría ser así:

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

El curry nunca es necesario, sí, ya que siempre puede crear una función anónima / flecha a partir de una función regular cuando los necesita, pero en algunas situaciones puede ser muy conveniente tener la función curry en comparación con la función regular (y en otras situaciones, es solo haciendo las cosas molestas y lentas).

Lie Ryan
fuente
2
"pero en algunas situaciones puede ser muy conveniente tener la función curry en comparación con la normal", ¿puede dar un ejemplo de eso? ¡Gracias!
Qiulang
@Qiulang un ejemplo es si tiene una serie de lógica de configuración que controla cómo llamar a una función que tiene muchos parámetros. Si no tiene una función currificada, a menudo tendrá que crear un objeto que tenga una API fluida, o proporcionar algún tipo de método clone_and_update (), o tendrá que crear una clase Builder separada para construir el parámetro de la función incrementalmente Un ejemplo típico de esto es el generador de consultas de un ORM. Con la función curry, puede llamar a la función como normal en cada paso.
Lie Ryan
@LieRyan En JavaScript , donde es tan trivial crear un "objeto" de opciones usando {}, no he encontrado que las clases de Builder sean muy útiles o comunes. ¿Puedes citar algunos ejemplos?
user949300
1
@ user949300 Crear veinte objetos con diez miembros que solo difieran en uno o dos parámetros no es más fácil en JS que en cualquier otro idioma. Con el objeto generador inmutable que usa una interfaz fluida, puede construir el objeto de configuración base y luego simplemente ramificarse para crear diferentes conjuntos de argumentos. Este tipo de patrón a menudo puede parecer demasiado pesado en el código de la aplicación, pero es bastante común para los autores de bibliotecas / marcos.
Mentira Ryan
1
Punto tomado, pero @LieRyan con el novedoso Object.assign()es bastante fácil ramificarse de una configuración base.
user949300