La curryfication : au coeur de la programmation fonctionnelle

Paul Martin
ELP-2018
Published in
4 min readJan 20, 2019

La curryfication… Derrière ce terme obscur se cache en fait un élément clé de la programmation fonctionnelle : vous en aurez peut-être déjà rencontré dans des langages comme Haskell, JavaScript ou encore Clojure.

Haskell Curry (1900–1982)

La curryfication, qu’est-ce que c’est?

Définition

Pour faire simple, on parle de curryfication — ou de currying — lorsque l’on transforme une fonction à N arguments en N fonctions prenant chacune un unique argument. Cela permet ainsi la création de fonctions pures. Bien que le terme “curryfication” soit un hommage au mathématicien américain Haskell Curry, Moses Schönfinkel fut le premier à aborder ce concept.

Exemple

En pseudocode, voilà à quoi ça ressemble :

curry (add (x,y)) => addcur x => lambda (y => x + y)

Ici, une fonction add(x,y) à deux arguments devient, une fois curryfiée, deux fonctions à un argument chacune : addcur(x) et une fonction abstraite dépendante de y.

En pratique

Afin d’y voir plus clair, observons la curryfication dans un code concret.

Fonction de définition d’un personnage, avant curryfication

Ici, nous avons une fonction persoDef à trois arguments — non curryfiée — permettant de définir un personnage ainsi qu’un objet de sa possession. La fonction doit être appelée en fournissant les trois arguments nécessaires : nom, objet, et couleur.

Avec cet exemple, on affiche en console :
“Jean a un chapeau de couleur rouge!”

Maintenant, observons la version curryfiée de cette fonction.

Fonction de définition d’un personnage, après curryfication

La fonction persoDefCurry(nom) ne prend effectivement qu’un seul argument, puis renvoie une fonction prenant un argument (objet), renvoyant ensuite une fonction à unique argument (couleur).

Notez la différence dans la structure de renseignement des arguments : ici, la syntaxe persoDefCurry(‘Jean’)(‘chapeau’)(‘rouge’) indique bien l’imbrication de trois fonctions.

En sortie, la console affiche également :
“Jean a un chapeau de couleur rouge!”

Nous sommes donc passés d’une unique fonction à trois arguments, à trois fonctions à argument unique.

D’accord mais… ça sert à quoi concrètement ?

Voyons un exemple où la curryfication s’avère pratique.

Tri avant curryfication

On a ici quatre personnages, possédant chacun un objet. On aimerait trouver parmi ces personnages, tous ceux et toutes celles qui possèdent un chapeau. Pour cela, on a créé une fonction possedeObjet(obj, perso) qui compare un objet soumis en argument à l’attribut objet du personnage soumis en deuxième argument, et retourne True si le personnage possède le dit objet.

On créé un array personnagesAvecChapeau, pour récupérer les personnages concernés. Dans sa définition, on applique la fonction .filter() à l’array personnages, filtrant les personnages x suivant la condition possedeObjet(‘chapeau’, x).

En appliquant ce code, on a en console :
“[{“nom”: “Jean”, “objet”: “chapeau”}, {“nom”: “Juliette”, “objet”: “chapeau”}]”

Ici, on appelle explicitement la fonction possedeObjet(obj, perso) à chaque itération de x, correspondant à chaque personnage de la liste. On peut simplifier ce tri grâce à un peu de curryfication :

Tri après curryfication

Ici, possedeObjet(obj, perso) est curryfié en possedeObjetCurry(obj)(perso). La fonction .filter() fournit implicitement x à la fonction curryfiée à chaque itération.

On passe du coup sur un code plus léger dans l’appel de .filter(), mais également dans un calcul de “plus bas niveau” car on traite la sous-fonction d’argument (perso) à chaque itération, et pas un appel complet de possedeObjetCurry(obj)(perso) — de la même manière qu’on utiliserait jean(objet) ou jeanChapeau(couleur).

Curryfication et application partielle, à ne pas confondre

La curryfication est souvent approchée à l’application partielle, qui consiste simplement en la réduction d’arité d’une fonction — l’arité étant le nombre d’arguments d’une fonction.

En clair, l’application partielle c’est fixer M arguments sur N d’une fonction f, afin de manipuler une fonction à N-M arguments. La curryfication, c’est transformer une fonction à N arguments en N fonctions à unique argument.

D’autre part, une application partielle n’a pas nécessairement de return type défini, tandis qu’une fonction curryfiée retourne toujours une autre fonction d’arité 1 jusqu’à épuisement des arguments.

Conclusion

Pour résumer, la curryfication — à ne pas confondre avec application partielle — est la transformation d’une fonction à N arguments en N fonctions à un argument, permettant ainsi une manipulation plus libre de la fonction originale, sans contrainte particulière sur un ou plusieurs arguments. Ce procédé nous permet également d’alléger le code, littéralement et/ou visuellement.

Bibliographie

Crédit image

Portrait de Haskell Curry :

Gleb.svechnikov [CC BY-SA 4.0 (https://creativecommons.org/licenses/by-sa/4.0)], from Wikimedia Commons

--

--