27 votes

Utilisation pratique des fonctions curry ?

Il existe des tonnes de tutoriels sur la façon de curer les fonctions, et autant de questions ici sur stackoverflow. Cependant, après avoir lu The Little Schemer, plusieurs livres, tutoriels, articles de blog et fils de discussion sur stackoverflow, je ne connais toujours pas la réponse à cette simple question : "Quel est l'intérêt du curry ?" Je comprends comment curer une fonction, mais pas le "pourquoi ?" derrière.

Quelqu'un pourrait-il m'expliquer les utilisations pratiques des fonctions curry (en dehors des langages qui ne permettent qu'un seul argument par fonction, où la nécessité d'utiliser le curry est bien sûr tout à fait évidente).

éditer : En prenant en compte certains exemples de TLS, quel est l'intérêt de

(define (action kind)
    (lambda (a b)
        (kind a b)))

à l'opposé de

(define (action kind a b)
    (kind a b))

Je ne vois que plus de code et pas de flexibilité supplémentaire...

22voto

Yasir Arsanukaev Points 6547

Une utilisation efficace des fonctions curry est la réduction de la quantité de code.

Considérons trois fonctions, dont deux sont presque identiques :

(define (add a b)
  (action + a b))

(define (mul a b)
  (action * a b))

(define (action kind a b)
  (kind a b))

Si votre code invoque add qui, à son tour, appelle action avec gentillesse + . De même avec mul .

Vous avez défini ces fonctions comme vous le feriez dans de nombreux langages impératifs populaires disponibles (certains d'entre eux ont inclus les lambdas, le currying et d'autres fonctionnalités que l'on trouve habituellement dans le monde fonctionnel, car tout cela est terriblement pratique).

Tous add et sum est d'envelopper l'appel à action avec les kind . Considérons maintenant les définitions curvilignes de ces fonctions :

(define add-curried
  ((curry action) +))

(define mul-curried
  ((curry action) *))

Ils sont devenus considérablement plus courts. Nous avons juste curé la fonction action en ne lui passant qu'un seul argument, le kind et on obtient la fonction curée qui accepte les deux autres arguments.

Cette approche vous permet d'écrire moins de code, avec un haut niveau de maintenabilité.

Imaginez juste cette fonction action serait immédiatement réécrite pour accepter 3 arguments supplémentaires. Sans curry, vous devriez réécrire vos implémentations de add et mul :

(define (action kind a b c d e)
  (kind a b c d e))

(define (add a b c d e)
  (action + a b c d e))

(define (mul a b c d e)
  (action * a b c d e))

Mais le currying vous a évité ce travail pénible et source d'erreurs ; vous n'avez pas à réécrire un seul symbole dans les fonctions add-curried et mul-curried du tout, car la fonction appelante fournirait la quantité nécessaire d'arguments transmis à action .

11voto

Bill Points 6709

Ils peuvent rendre le code plus facile à lire. Considérons les deux extraits Haskell suivants :

lengths :: [[a]] -> [Int]
lengths xs = map length xs

lengths' :: [[a]] -> [Int]
lengths' = map length

Pourquoi donner un nom à une variable que vous n'allez pas utiliser ?

Les fonctions curry sont également utiles dans ce genre de situation :

doubleAndSum ys = map (\xs -> sum (map (*2) xs) ys

doubleAndSum' = map (sum . map (*2))

La suppression de ces variables supplémentaires rend le code plus facile à lire et il n'est pas nécessaire que vous gardiez mentalement à l'esprit ce que xs est et ce que ys est.

HTH.

4voto

Francesco Points 2139

Vous pouvez voir le currying comme une spécialisation. Choisissez quelques valeurs par défaut et laissez l'utilisateur (peut-être vous-même) avec un outil spécialisé, plus simple et plus efficace. expressif , fonction.

3voto

Artyom Shalkhakov Points 659

Je pense que le currying est une manière traditionnelle de gérer les fonctions générales n-aires, à condition que les seules que l'on puisse définir soient unaires.

Par exemple, dans le lambda calculus (dont sont issus les langages de programmation fonctionnelle), il n'y a que des abstractions à une variable (ce qui se traduit par des fonctions unaires dans les FPL). En ce qui concerne le lambda calculus, je pense qu'il est plus facile de prouver des choses sur un tel formalisme puisque vous n'avez pas besoin de traiter le cas des fonctions n-aires (puisque vous pouvez représenter n'importe quelle fonction n-aire par un certain nombre de fonctions unaires grâce au currying).

(D'autres ont déjà abordé certaines des implications pratiques de cette décision, je m'arrêterai donc là).

2voto

u0b34a0f6ae Points 14874

Utilisation de all :: (a -> Bool) -> [a] -> Bool avec un prédicat curé.

all (`elem` [1,2,3]) [0,3,4,5]

Les opérateurs infixes de Haskell peuvent être curés des deux côtés, de sorte que vous pouvez facilement curer le côté aiguille ou le côté conteneur de la fonction elem fonction (is-element-of).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X