J'ai vu des références à des fonctions au curry dans plusieurs articles et blogs mais je ne trouve pas de bonne explication (ou au moins une explication!)
653
J'ai vu des références à des fonctions au curry dans plusieurs articles et blogs mais je ne trouve pas de bonne explication (ou au moins une explication!)
curry
etuncurry
de Haskell. Ce qui est important ici, c'est que ces isomorphismes sont fixés au préalable, et donc "intégrés" dans le langage.add x y = x+y
(curry) est différent deadd (x, y)=x+y
(uncurried)Réponses:
Le currying consiste à décomposer une fonction qui prend plusieurs arguments en une série de fonctions qui ne prennent chacune qu'un seul argument. Voici un exemple en JavaScript:
Il s'agit d'une fonction qui prend deux arguments, a et b, et renvoie leur somme. Nous allons maintenant curry cette fonction:
Il s'agit d'une fonction qui prend un argument, a, et renvoie une fonction qui prend un autre argument, b, et cette fonction retourne leur somme.
La première instruction renvoie 7, comme l'instruction add (3, 4). La deuxième instruction définit une nouvelle fonction appelée add3 qui ajoutera 3 à son argument. C'est ce que certains appellent une fermeture. La troisième instruction utilise l'opération add3 pour ajouter 3 à 4, produisant à nouveau 7 en conséquence.
la source
[1, 2, 3, 4, 5]
que vous souhaitez multiplier par un nombre arbitraire. Dans Haskell, je peux écriremap (* 5) [1, 2, 3, 4, 5]
pour multiplier la liste entière par5
, et ainsi générer la liste[5, 10, 15, 20, 25]
.map
doit être une fonction qui ne prend qu'un seul argument - un élément de la liste. La multiplication - en tant que concept mathématique - est une opération binaire; il faut 2 arguments. Cependant, dans Haskell*
est une fonction curry, similaire à la deuxième version deadd
dans cette réponse. Le résultat de(* 5)
est une fonction qui prend un seul argument et le multiplie par 5, et qui nous permet de l'utiliser avec map.Dans une algèbre de fonctions, traiter des fonctions qui prennent plusieurs arguments (ou un argument équivalent qui est un tuple N) est quelque peu inélégant - mais, comme l'a démontré Moses Schönfinkel (et, indépendamment, Haskell Curry), ce n'est pas nécessaire: tout ce que vous besoin sont des fonctions qui prennent un argument.
Alors, comment gérez-vous quelque chose que vous exprimeriez naturellement, disons
f(x,y)
? Eh bien, vous prenez cela comme équivalent àf(x)(y)
-f(x)
, appelez-leg
, est une fonction, et vous appliquez cette fonction ày
. En d'autres termes, vous n'avez que des fonctions qui prennent un argument - mais certaines de ces fonctions renvoient d'autres fonctions (qui prennent également un argument ;-).Comme d'habitude, wikipedia a une belle entrée récapitulative à ce sujet, avec de nombreux conseils utiles (y compris probablement ceux concernant vos langues préférées ;-) ainsi qu'un traitement mathématique légèrement plus rigoureux.
la source
div :: Integral a => a -> a -> a
- notez ces multiples flèches? "Mapper une fonction mappant une à une" est une lecture ;-). Vous pouvez utiliser un argument (unique) de tuple pourdiv
& c, mais ce serait vraiment anti-idiomatique dans Haskell.Voici un exemple concret:
Supposons que vous ayez une fonction qui calcule la force gravitationnelle agissant sur un objet. Si vous ne connaissez pas la formule, vous pouvez la trouver ici . Cette fonction prend les trois paramètres nécessaires comme arguments.
Maintenant, étant sur la terre, vous voulez seulement calculer les forces des objets sur cette planète. Dans un langage fonctionnel, vous pourriez passer la masse de la terre à la fonction et l'évaluer ensuite partiellement. Ce que vous obtiendrez en retour est une autre fonction qui ne prend que deux arguments et calcule la force gravitationnelle des objets sur terre. C'est ce qu'on appelle le curry.
la source
Le curry est une transformation qui peut être appliquée aux fonctions pour leur permettre de prendre un argument de moins qu'auparavant.
Par exemple, en F # vous pouvez définir une fonction ainsi: -
Ici, la fonction f prend les paramètres x, y et z et les additionne ainsi: -
Renvoie 6.
D'après notre définition, nous pouvons donc définir la fonction de curry pour f: -
Où 'fun x -> fx' est une fonction lambda équivalente à x => f (x) en C #. Cette fonction entre la fonction que vous souhaitez curry et renvoie une fonction qui prend un seul argument et renvoie la fonction spécifiée avec le premier argument défini sur l'argument d'entrée.
En utilisant notre exemple précédent, nous pouvons obtenir un curry de f ainsi: -
On peut alors faire ce qui suit: -
Ce qui nous donne une fonction f1 qui équivaut à f1 yz = 1 + y + z. Cela signifie que nous pouvons faire ce qui suit: -
Qui renvoie 6.
Ce processus est souvent confondu avec «application de fonction partielle» qui peut être définie ainsi: -
Bien que nous puissions l'étendre à plusieurs paramètres, à savoir: -
Une application partielle prendra la fonction et le (s) paramètre (s) et retournera une fonction qui nécessite un ou plusieurs paramètres en moins, et comme les deux exemples précédents le montrent est implémenté directement dans la définition de fonction F # standard afin que nous puissions obtenir le résultat précédent ainsi: -
Qui retournera un résultat de 6.
En conclusion:-
La différence entre le curry et l'application d'une fonction partielle est que: -
Le curry prend une fonction et fournit une nouvelle fonction acceptant un seul argument et renvoyant la fonction spécifiée avec son premier argument défini sur cet argument. Cela nous permet de représenter des fonctions avec plusieurs paramètres comme une série de fonctions à argument unique . Exemple:-
L'application de fonction partielle est plus directe - elle prend une fonction et un ou plusieurs arguments et renvoie une fonction avec les n premiers arguments définis sur les n arguments spécifiés. Exemple:-
la source
Cela peut être un moyen d'utiliser des fonctions pour créer d'autres fonctions.
En javascript:
Nous permettrait de l'appeler ainsi:
Lorsque cela s'exécute, le
10
est transmis en tant quex
;ce qui signifie que nous retournons cette fonction:
Alors quand tu appelles
vous appelez vraiment:
Donc, si vous faites cela:
c'est la même chose que:
Donc, notre
addTen()
ajoute toujours dix à tout ce que nous transmettons. Nous pouvons créer des fonctions similaires de la même manière:Maintenant, la question de suivi évidente est pourquoi diable voudriez-vous jamais faire cela? Cela transforme ce qui était une opération enthousiaste
x + y
en une opération qui peut être exécutée paresseusement, ce qui signifie que nous pouvons faire au moins deux choses: 1. mettre en cache des opérations coûteuses 2. réaliser des abstractions dans le paradigme fonctionnel.Imaginez que notre fonction au curry ressemble à ceci:
Nous pourrions appeler cette fonction une fois, puis faire circuler le résultat à utiliser dans de nombreux endroits, ce qui signifie que nous ne faisons qu'une fois les choses coûteuses en calcul:
Nous pouvons obtenir des abstractions de la même manière.
la source
Une fonction curry est une fonction de plusieurs arguments réécrits de telle sorte qu'elle accepte le premier argument et renvoie une fonction qui accepte le deuxième argument et ainsi de suite. Cela permet aux fonctions de plusieurs arguments d'avoir certains de leurs arguments initiaux partiellement appliqués.
la source
map
une fonctionf
sur une liste de listes,xss
vous pouvez le fairemap (map f) xss
.Voici un exemple de jouet en Python:
(Il suffit d'utiliser la concaténation via + pour éviter toute distraction pour les programmeurs non Python.)
Modification à ajouter:
Voir http://docs.python.org/library/functools.html?highlight=partial#functools.partial , qui montre également la distinction entre l'objet partiel et la fonction dans la façon dont Python l'implémente.
la source
Currying traduit une fonction de callable as
f(a, b, c)
en callable asf(a)(b)(c)
.Sinon, le curry est lorsque vous décomposez une fonction qui prend plusieurs arguments en une série de fonctions qui font partie des arguments.
Littéralement, le curry est une transformation des fonctions: d'une manière d'appeler à une autre. En JavaScript, nous créons généralement un wrapper pour conserver la fonction d'origine.
Le curry n'appelle pas de fonction. Cela le transforme simplement.
Faisons la fonction curry qui effectue le curry pour les fonctions à deux arguments. En d'autres termes,
curry(f)
pour deux arguments,f(a, b)
cela se traduit parf(a)(b)
Comme vous pouvez le voir, l'implémentation est une série de wrappers.
curry(func)
est un wrapperfunction(a)
.sum(1)
, l'argument est enregistré dans l'environnement lexical et un nouveau wrapper est renvoyéfunction(b)
.sum(1)(2)
finalement, ilfunction(b)
fournit 2 et il passe l'appel à la somme multi-arguments d'origine.la source
Si vous comprenez que
partial
vous êtes à mi-chemin. L'idée departial
est de pré-appliquer des arguments à une fonction et de redonner une nouvelle fonction qui ne veut que les arguments restants. Lorsque cette nouvelle fonction est appelée, elle inclut les arguments préchargés ainsi que les arguments qui lui ont été fournis.Dans Clojure
+
est une fonction mais pour que les choses soient clairement claires:Vous savez peut-être que la
inc
fonction ajoute simplement 1 au nombre passé.Construisons-le nous-mêmes en utilisant
partial
:Ici, nous renvoyons une autre fonction qui a 1 chargé dans le premier argument de
add
. Commeadd
prend deux arguments, la nouvelleinc
fonction ne veut que l'b
argument - pas 2 arguments comme avant car 1 a déjà été partiellement appliqué. C'est doncpartial
un outil à partir duquel créer de nouvelles fonctions avec des valeurs par défaut présupposées. C'est pourquoi dans un langage fonctionnel, les fonctions ordonnent souvent les arguments du général au spécifique. Cela facilite la réutilisation de telles fonctions à partir desquelles on peut construire d'autres fonctions.Imaginez maintenant si le langage était suffisamment intelligent pour comprendre de manière introspective qui
add
voulait deux arguments. Lorsque nous lui avons transmis un argument, plutôt que de rechigner, que se passerait-il si la fonction appliquait partiellement l'argument que nous lui avons transmis en notre nom, comprenant que nous voulions probablement fournir l'autre argument plus tard? On pourrait alors définirinc
sans utiliser explicitementpartial
.C'est ainsi que certaines langues se comportent. Il est exceptionnellement utile lorsque l'on souhaite composer des fonctions en transformations plus importantes. Cela conduirait à des transducteurs.
la source
J'ai trouvé cet article et l'article auquel il fait référence utiles pour mieux comprendre le curry: http://blogs.msdn.com/wesdyer/archive/2007/01/29/currying-and-partial-function-application.aspx
Comme les autres l'ont mentionné, c'est juste un moyen d'avoir une fonction à un paramètre.
Ceci est utile dans la mesure où vous n'avez pas à supposer combien de paramètres seront transmis, vous n'avez donc pas besoin de 2 paramètres, 3 paramètres et 4 fonctions de paramètres.
la source
Comme toutes les autres réponses, le curry aide à créer des fonctions partiellement appliquées. Javascript ne fournit pas de support natif pour le curry automatique. Par conséquent, les exemples fournis ci-dessus peuvent ne pas aider au codage pratique. Il y a un excellent exemple dans livescript (qui compile essentiellement en js) http://livescript.net/
Dans l'exemple ci-dessus, lorsque vous avez donné moins d'arguments, le script de vie génère une nouvelle fonction curry pour vous (double)
la source
Curry peut simplifier votre code. C'est l'une des principales raisons de l'utiliser. Le curry est un processus de conversion d'une fonction qui accepte n arguments en n fonctions qui n'acceptent qu'un seul argument.
Le principe est de passer les arguments de la fonction passée, en utilisant la propriété de fermeture (fermeture), de les stocker dans une autre fonction et de la traiter comme une valeur de retour, et ces fonctions forment une chaîne, et les arguments finaux sont passés pour terminer l'opération.
L'avantage de ceci est qu'il peut simplifier le traitement des paramètres en traitant un paramètre à la fois, ce qui peut également améliorer la flexibilité et la lisibilité du programme. Cela rend également le programme plus gérable. La division du code en morceaux plus petits le rendrait également réutilisable.
Par exemple:
Je peux aussi faire ...
C'est très bien pour rendre le code complexe soigné et gérer les méthodes non synchronisées, etc.
la source
Une fonction curry est appliquée à plusieurs listes d'arguments, au lieu d'une seule.
Voici une fonction régulière, non curry, qui ajoute deux paramètres Int, x et y:
Voici une fonction similaire qui est curry. Au lieu d'une liste de deux paramètres Int, vous appliquez cette fonction à deux listes d'un paramètre Int chacune:
Ce qui se passe ici, c'est que lorsque vous appelez
curriedSum
, vous obtenez en fait deux invocations de fonctions traditionnelles consécutives. La première invocation de fonction prend un seul paramètre Int nomméx
et renvoie une valeur de fonction pour la deuxième fonction. Cette deuxième fonction prend le paramètre Inty
.Voici une fonction nommée
first
qui fait dans l'esprit ce quecurriedSum
ferait la première invocation de fonction traditionnelle :Appliquer 1 à la première fonction - en d'autres termes, invoquer la première fonction et passer à 1 - donne la deuxième fonction:
L'application de 2 à la deuxième fonction donne le résultat:
la source
Un exemple de curry serait lorsque vous avez des fonctions dont vous ne connaissez actuellement qu'un seul paramètre:
Par exemple:
Ici, puisque vous ne connaissez pas le deuxième paramètre de rappel lors de son envoi,
performAsyncRequest(_:)
vous devrez créer un autre lambda / fermeture pour envoyer celui-ci à la fonction.la source
func callback
retourne? Il est appelé @callback(str)
donclet callback = callback(str)
, le rappel n'est que la valeur de retour defunc callback
func callback(_:data:)
accepte deux paramètres, ici je ne lui en donne qu'un, leString
, donc il attend le suivant (NSData
), c'est pourquoi maintenantlet callback
une autre fonction attend que les données soient transmisesVoici l'exemple de générique et la version la plus courte pour le curry de fonction avec n non. de params.
la source
Vous trouverez ici une explication simple de l'implémentation du curry en C #. Dans les commentaires, j'ai essayé de montrer comment le curry peut être utile:
la source
Le curry est l'une des fonctions d'ordre supérieur de Java Script.
Le currying est une fonction de nombreux arguments qui est réécrite de telle sorte qu'il prend le premier argument et renvoie une fonction qui à son tour utilise les arguments restants et renvoie la valeur.
Confus?
Voyons un exemple,
Ceci est similaire à la fonction de curry suivante,
Alors, que signifie ce code?
Maintenant, relisez la définition,
Le currying est une fonction de nombreux arguments qui est réécrite de manière à prendre le premier argument et à renvoyer une fonction qui à son tour utilise les arguments restants et renvoie la valeur.
Encore confus? Laissez-moi vous expliquer en profondeur!
Lorsque vous appelez cette fonction,
Il vous renverra une fonction comme celle-ci,
Donc, cela s'appelle des fonctions d'ordre supérieur. Cela signifie que l'invocation d'une fonction à son tour renvoie une autre fonction est une définition exacte pour une fonction d'ordre supérieur. C'est le plus grand avantage de la légende, Java Script. Revenez donc au curry,
Cette ligne passera le deuxième argument à la fonction curryAdd.
qui à son tour résulte,
J'espère que vous comprenez l'utilisation du curry ici. Donc, en ce qui concerne les avantages,
Pourquoi Currying?
Il utilise la réutilisabilité du code. Moins de code, moins d'erreur. Vous pouvez demander en quoi c'est moins de code?
Je peux le prouver avec le script ECMA 6 nouvelles fonctions de flèche de fonctionnalité.
Oui! ECMA 6, fournissez-nous la merveilleuse fonctionnalité appelée fonctions de flèche,
Avec l'aide de la fonction flèche, nous pouvons écrire la fonction ci-dessus comme suit,
Cool non?
Donc, moins de code et moins de bugs !!
Avec l'aide de ces fonctions d'ordre supérieur, on peut facilement développer un code sans bogue.
Je te met au défi!
J'espère que vous avez compris ce qui est curry. N'hésitez pas à commenter ici si vous avez besoin de clarifications.
Merci bonne journée!
la source
Il existe un exemple de "Currying in ReasonML".
la source