Comment concilier Javascript avec le curry et la composition fonctionnelle

J'adore curry, mais il y a quelques raisons pour lesquelles un petit nombre de JavaScript devs rejettent cette technique:

  1. Préoccupations esthétiques concernant le motif typique du curry: f(x) (y) (z)
  2. Préoccupations concernant les pénalités de performance en raison du nombre accru d'appels de fonctions
  3. Inquiétudes concernant les problèmes de débogage en raison des nombreuses fonctions anonymes imbriquées
  4. Préoccupations quant à la lisibilité du style sans points (curry en relation avec la composition)

Existe-t-il une approche qui peut atténuer ces préoccupations afin que mes collègues ne me déteste pas?

L'approche dominante actuelle prévoit que chaque fonction multi-argument est enveloppée dans une fonction de curry dynamique. Bien que cela contribue à la préoccupation n ° 1, les autres restent intacts. Voici une approche alternative.

Fonctions compostables

Une fonction composable n'est curry que dans son dernier argument. Pour les distinguer des fonctions multi-arguments normales, je les nomme avec un trait de soulignement final (la dénomination est difficile).

 const comp_ = (f, g) => x => f(g(x)); // composable function const foldl_ = (f, acc) => xs => xs.reduce((acc, x, i) => f(acc, x, i), acc); const curry = f => y => x => f(x, y); // fully curried function const drop = (xs, n) => xs.slice(n); // normal, multi argument function const add = (x, y) => x + y; const sum = foldl_(add, 0); const dropAndSum = comp_(sum, curry(drop) (1)); console.log( dropAndSum([1,2,3,4]) // 9 ); 

Note: @ftor a répondu à sa propre question. Ceci est un accompagnement direct de cette réponse.

Vous êtes déjà un génie

Je pense que vous avez peut-être ré-imaginé la fonction partial – du moins en partie!

 const partial = (f, ...xs) => (...ys) => f(...xs, ...ys); 

Et c'est contre-partie, partialRight

 const partialRight = (f, ...xs) => (...ys) => f(...ys, ...xs); 

partial prend une fonction, certains args ( xs ), et renvoie toujours une fonction qui prend plus d'args ( ys ), puis applique f pour (...xs, ...ys)


Remarques initiales

Le contexte de cette question est défini dans la façon dont le curry et la composition peuvent jouer bien avec une grande base d'utilisateurs de codeurs. Mes remarques seront dans le même contexte

  • Juste parce qu'une fonction peut renvoyer une fonction ne signifie pas qu'elle est curry – accrocher sur un _ pour signifier qu'une fonction attend de plus args est déroutant. Rappelez-vous que le currying (ou l'application de fonction partielle) résume l'arity, donc nous ne savons jamais quand un appel de fonction entraînera la valeur d'un calcul ou une autre fonction en attente d'appel.

  • curry ne doit pas faire basculer les arguments; Cela va causer de sérieux moments pour votre codeur

  • Si nous allons créer une enveloppe pour reduce , l'enveloppe reduceRight devrait être cohérente – par exemple, votre foldl utilise f(acc, x, i) mais votre foldr utilise f(x, acc, i) – cela causera beaucoup De la douleur parmi les collègues qui ne connaissent pas ces choix

Pour la prochaine section, je vais remplacer votre composable par partial , supprimer _ -suffixes et réparer le wrapper foldr


Fonctions compostables

 const partial = (f, ...xs) => (...ys) => f(...xs, ...ys); const partialRight = (f, ...xs) => (...ys) => f(...ys, ...xs); const comp = (f, g) => x => f(g(x)); const foldl = (f, acc, xs) => xs.reduce(f, acc); const drop = (xs, n) => xs.slice(n); const add = (x, y) => x + y; const sum = partial(foldl, add, 0); const dropAndSum = comp(sum, partialRight(drop, 1)); console.log( dropAndSum([1,2,3,4]) // 9 );