Curryfication

Un article de Wikipédia, l'encyclopédie libre.
Aller à : navigation, rechercher

En programmation fonctionnelle, la curryfication désigne l'opération qui fait passer une fonction à plusieurs arguments à une fonction à un argument qui retourne une fonction prenant le reste des arguments. L'opération inverse est évidemment possible. La curryfication permet de créer des fonctions pures.

Le terme vient du nom du mathématicien américain Haskell Curry, bien que cette opération fût introduite pour la première fois par Moses Schönfinkel.

Définition[modifier | modifier le code]

Imaginons une fonction add(x, y) qui prend deux arguments et en renvoie la somme. Une fois curryfiée, on aurait une fonction add(x) qui prend un argument et renvoie une fonction qui prend le deuxième argument. En pseudo-langage :

  curry (add (x,y)) → add x → lambda (y → x + y)

La curryfication permet l'application partielle : si on appelle la fonction curryfiée avec l'argument 3, on récupère une fonction qui ajoute 3 à son argument.

Exemples[modifier | modifier le code]

Haskell[modifier | modifier le code]

En Haskell voici une fonction non-curryfiée :

 uncurried_add (x, y) = x + y

et la même après curryfication:

  curried_add x y = x + y

ou (la barre \ signifie lambda et sert pour définir des fonctions anonymes) :

 curried_add = \x → \y → x + y

Et voici une application partielle :

 add_three = curried_add 3 

Remarques[modifier | modifier le code]

La fonction add_three est dite pure.

La curryfication peut se faire à la main ou bien par un programme. Pour les fonctions à deux arguments, voici ces programmes en Haskell :

 curry f x y = f(x,y)
 uncurry f (x, y) = f x y

Python[modifier | modifier le code]

Même fonction en Python :

def uncurried_add (x, y):
    return x + y
def curried_add (x):
    return lambda y: x + y
print uncurried_add(3, 4)
add_three = curried_add(3)
print add_three(4)

Caml[modifier | modifier le code]

Même fonction en Caml :

  let uncurried_add (x,y) = x + y;; (* Type de la fonction : (entier * entier) -> entier *)
  let curried_add x y = x + y;; (* Type de la fonction : entier -> entier -> entier *)
 
  uncurried_add(3,4);; (* Retourne 7. Type de la valeur retournée : entier. *)
 
  curried_add 3;; (* Retourne la fonction qui ajoute 3. Type de la valeur retournée : entier -> entier. *)
  (curried_add 3) 4;; (* Crée la fonction qui ajoute 3 et l'applique à l'entier 4. Retourne 7. Type de la valeur retournée : entier. *)
 
  let add_three = curried_add 3;; (* Définit la fonction add_three comme la fonction qui ajoute 3 à son argument. *)
  add_three 4;; (* Applique add_three à 4. Retourne 7. *)

Ruby[modifier | modifier le code]

Dans le version 1.9 de Ruby, la classe Proc fournit à ses instances la méthode curry. Proc#curry retourne un objet proc curryfié. La méthode prend en argument un argument facultatif : l'arité qui permet des processus plus fins que nous ne détaillerons pas ici.

  p = Proc.new { |a,b| a+b } => #<Proc:0x00000000ff5208> 
 
  #Appel classique
  p.call(3) => "TypeError: nil can't be coerced into Fixnum"
  p.call(3,4) => 7
 
  #Utilisation de la méthode curry
  p.curry[3][4] => 7
  #renvoie un Fixnum, car il y a eu le bon nombre d'arguments fournis.
 
  a = p.curry[3] => #<Proc:0x00000000f9b0c8>
  a.call(5) => 8
  a.call(10) => 13

Scheme[modifier | modifier le code]

  (define uncurried-add (lambda (x y)
                                (+ x y)))
  (define curried_add (lambda (x) (lambda (y) (+ x y))))
  (define add-three (curried_add 3))

Scala[modifier | modifier le code]

   def uncurried_add(x : Int, y : Int) = x + y         // |-> Int
   // Après currying : 
   def curried_add0(x : Int)(y : Int) = x + y          // |-> Int
   // Ce qui équivaut (si on décompose) à : 
   def curried_add1 (x : Int) = (y : Int) =>  x + y    // |-> Int => Int 
   // Ou encore à : 
   def curried_add2 = (x : Int) => (y : Int) =>  x + y // |-> Int => (Int => Int) 
 
// applications partielles :
 
   def add_three0 = curried_add0(3)_ // retourne une fonction de type : Int => Int
   curried_add0(3)(5) // Retourne 8
   add_three0(5) // Retourne 8
 
   def add_three1 = curried_add1(3) // retourne une fonction de type : Int => Int
   curried_add1(3)(5) // Retourne 8
   add_three1(5) // Retourne 8
 
   def add_three2 = curried_add2(3) // retourne une fonction de type : Int => Int
   curried_add2(3)(5) // Retourne 8
   add_three2(5) // Retourne 8

Tcl[modifier | modifier le code]

proc uncurried_add {x y} {expr {$x + $y}}
proc curried_add x {list apply [list y [format {expr {%d + $y}} $x]]}

Perl 6[modifier | modifier le code]

Un JAPH qui est un exemple de curryfication en Perl 6 :

 sub japh (Str $lang) { say "just another $lang hacker"; }
 my &perl6Japh := &japh.assuming("Perl6");
 perl6Japh();

Voir aussi[modifier | modifier le code]