Qu'est-ce que le «curry»?

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!)

Ben
la source
12
[Laissé en commentaire, car il sera inutile aux non-mathématiciens.] Selon la définition d'une catégorie fermée cartésienne, il existe une famille fixe d'adjonctions (naturellement paramétrées par A) entre X -> X x A et X -> X ^ A. Les isomorphismes hom (X x A, Y) <-> hom (X, Y ^ A) sont les fonctions curryet uncurryde 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.
Alexandre C.
3
Il y a un bon tutoriel ici pour le curry dans haskell learnnyouahaskell.com/higher-order-functions#curried-functions de courts commentaires est que add x y = x+y(curry) est différent de add (x, y)=x+y(uncurried)
Jaider

Réponses:

872

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:

function add (a, b) {
  return a + b;
}

add(3, 4); // returns 7

Il s'agit d'une fonction qui prend deux arguments, a et b, et renvoie leur somme. Nous allons maintenant curry cette fonction:

function add (a) {
  return function (b) {
    return a + b;
  }
}

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.

add(3)(4);

var add3 = add(3);

add3(4);

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.

Kyle Cronin
la source
236
Dans un sens pratique, comment puis-je utiliser ce concept?
Strawberry
43
@Strawberry, disons par exemple que vous avez une liste de nombres dans un [1, 2, 3, 4, 5]que vous souhaitez multiplier par un nombre arbitraire. Dans Haskell, je peux écrire map (* 5) [1, 2, 3, 4, 5]pour multiplier la liste entière par 5, et ainsi générer la liste [5, 10, 15, 20, 25].
nyson
62
Je comprends ce que fait la fonction de carte, mais je ne sais pas si je comprends le point que vous essayez d'illustrer pour moi. Voulez-vous dire que la fonction de carte représente le concept de curry?
Strawberry
78
@Strawberry Le premier argument à mapdoit ê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 de adddans 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.
Doval
26
@Strawberry Ce qui est bien avec les langages fonctionnels comme Standard ML ou Haskell, c'est que vous pouvez obtenir du curry "gratuitement". Vous pouvez définir une fonction multi-arguments comme vous le feriez dans n'importe quel autre langage, et vous en obtenez automatiquement une version au curry, sans avoir à ajouter vous-même un tas de lambdas. Ainsi, vous pouvez produire de nouvelles fonctions qui prennent moins d'arguments de n'importe quelle fonction existante sans trop de tracas et qui facilitent leur transmission à d'autres fonctions.
Doval
125

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-le g, 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.

Alex Martelli
la source
1
Je suppose un commentaire similaire au mien ci-dessus - je n'ai pas vu que les langages fonctionnels limitent les fonctions à la prise d'un seul argument. Suis-je trompé?
Eric M
1
@hoohoo: Les langages fonctionnels ne limitent généralement pas les fonctions à un seul argument. Cependant, à un niveau plus bas et plus mathématique, il est beaucoup plus facile de traiter des fonctions qui ne prennent qu'un seul argument. (Dans le calcul lambda, par exemple, les fonctions ne prennent qu'un seul argument à la fois.)
Sam DeFabbia-Kane
1
D'ACCORD. Une autre question alors. Est-ce que ce qui suit est une vraie déclaration? Le calcul lambda peut être utilisé comme modèle de programmation fonctionnelle mais la programmation fonctionnelle n'est pas nécessairement appliquée au calcul lambda.
Eric M
7
Comme le notent les pages wikipedia, la plupart des langages FP "embellissent" ou "augmentent" le calcul lambda (par exemple avec certaines constantes et types de données) plutôt que de simplement "l'appliquer", mais ce n'est pas si proche. BTW, qu'est-ce qui vous donne l'impression que par exemple Haskell NE "restreint pas les fonctions à prendre un seul argument"? C'est sûr, bien que cela ne soit pas pertinent grâce au curry; par exemple 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 pour div& c, mais ce serait vraiment anti-idiomatique dans Haskell.
Alex Martelli
@Alex - wrt Haskell & arg count, je n'ai pas passé beaucoup de temps sur Haskell, et c'était il y a quelques semaines. C'était donc une erreur facile à faire.
Eric M
101

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.

Shea Daniels
la source
2
Par curiosité, la bibliothèque Prototype pour JavaScript propose une fonction "curry" qui fait à peu près exactement ce que vous avez expliqué ici: prototypejs.org/api/function/curry
shuckster
Nouveau lien de fonction Curry PrototypeJS. prototypejs.org/doc/latest/language/Function/prototype/curry/…
Richard Ayotte
7
Cela ressemble à une application partielle pour moi. Ma compréhension est que si vous appliquez le curry, vous pouvez créer des fonctions avec un seul argument et les composer pour former des fonctions plus compliquées. Suis-je en train de manquer quelque chose?
neontapir
9
@neontapir est correct. Ce que Shea a décrit n'est pas le curry. Il s'agit d'une application partielle. Si une fonction à trois arguments est curry et que vous l'appelez comme f (1), ce que vous obtenez n'est pas une fonction à deux arguments. Vous récupérez une fonction à un argument qui renvoie une autre fonction à un argument. Une fonction au curry ne peut recevoir qu'un seul argument. La fonction curry dans PrototypeJS n'est pas non plus curry. C'est une application partielle.
MindJuice
non (à l'évaluation partielle) et non (au curry). c'est ce qu'on appelle une application partielle. le curry est nécessaire pour l'activer.
Will Ness
47

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: -

let f x y z = x + y + z

Ici, la fonction f prend les paramètres x, y et z et les additionne ainsi: -

f 1 2 3

Renvoie 6.

D'après notre définition, nous pouvons donc définir la fonction de curry pour f: -

let curry f = fun x -> f x

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: -

let curryf = curry f

On peut alors faire ce qui suit: -

let f1 = curryf 1

Ce qui nous donne une fonction f1 qui équivaut à f1 yz = 1 + y + z. Cela signifie que nous pouvons faire ce qui suit: -

f1 2 3

Qui renvoie 6.

Ce processus est souvent confondu avec «application de fonction partielle» qui peut être définie ainsi: -

let papply f x = f x

Bien que nous puissions l'étendre à plusieurs paramètres, à savoir: -

let papply2 f x y = f x y
let papply3 f x y z = f x y z
etc.

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: -

let f1 = f 1
f1 2 3

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:-

let f x y z = x + y + z
let curryf = curry f
let f1 = curryf 1
let f2 = curryf 2
f1 2 3
6
f2 1 3
6

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:-

let f x y z = x + y + z
let f1 = f 1
let f2 = f 2
f1 2 3
6
f2 1 3
6
ljs
la source
Donc, les méthodes en C # devraient être analysées avant de pouvoir être appliquées partiellement?
cdmckay
"Cela nous permet de représenter des fonctions avec plusieurs paramètres comme une série de fonctions à argument unique" - parfait, cela m'a bien éclairé. Merci
Analyse floue
44

Cela peut être un moyen d'utiliser des fonctions pour créer d'autres fonctions.

En javascript:

let add = function(x){
  return function(y){ 
   return x + y
  };
};

Nous permettrait de l'appeler ainsi:

let addTen = add(10);

Lorsque cela s'exécute, le 10est transmis en tant que x;

let add = function(10){
  return function(y){
    return 10 + y 
  };
};

ce qui signifie que nous retournons cette fonction:

function(y) { return 10 + y };

Alors quand tu appelles

 addTen();

vous appelez vraiment:

 function(y) { return 10 + y };

Donc, si vous faites cela:

 addTen(4)

c'est la même chose que:

function(4) { return 10 + 4} // 14

Donc, notre addTen()ajoute toujours dix à tout ce que nous transmettons. Nous pouvons créer des fonctions similaires de la même manière:

let addTwo = add(2)       // addTwo(); will add two to whatever you pass in
let addSeventy = add(70)  // ... and so on...

Maintenant, la question de suivi évidente est pourquoi diable voudriez-vous jamais faire cela? Cela transforme ce qui était une opération enthousiaste x + yen 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:

let doTheHardStuff = function(x) {
  let z = doSomethingComputationallyExpensive(x)
  return function (y){
    z + y
  }
}

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:

let finishTheJob = doTheHardStuff(10)
finishTheJob(20)
finishTheJob(30)

Nous pouvons obtenir des abstractions de la même manière.

Adzz
la source
5
La meilleure explication étape par étape d'un processus intrinsèquement séquentiel que j'ai vu ici, et peut-être la meilleure réponse la plus explicative du lot.
4
@jonsilver Je dirais le contraire, pas une bonne explication. Je suis d'accord qu'il est bon pour expliquer l'exemple posé, mais les gens ont tendance à penser par défaut, "ouais parfaitement clair mais j'aurais pu faire la même chose d'une autre manière alors à quoi bon le curry?" En d'autres termes, je souhaite qu'il y ait juste assez de contexte ou d'explication pour éclairer non seulement le fonctionnement du curry, mais aussi pourquoi ce n'est pas une observation inutile et triviale par rapport à d'autres façons d'en ajouter dix.
whitneyland
29

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.

Jon Harrop
la source
5
"Cela permet aux fonctions de plusieurs arguments d'avoir certains de leurs arguments initiaux partiellement appliqués." - pourquoi est-ce bénéfique?
acarlon
5
Les fonctions @acarlon sont souvent appelées à plusieurs reprises avec un ou plusieurs arguments identiques. Par exemple, si vous voulez mapune fonction fsur une liste de listes, xssvous pouvez le faire map (map f) xss.
Jon Harrop
1
Merci, c'est logique. J'ai fait un peu plus de lecture et ça s'est mis en place.
acarlon
4
Je pense que cette réponse est juste d'une manière concise. Le "currying" est le processus consistant à prendre la fonction de plusieurs arguments et à la convertir en une série de fonctions qui prennent chacune un seul argument et retournent une fonction d'un seul argument, ou dans le cas de la fonction finale, retournent le résultat réel . Cela peut être fait automatiquement pour vous par la langue, ou vous pouvez appeler une fonction curry () dans d'autres langues pour générer la version curry. Notez que l'appel d'une fonction curry avec un paramètre n'est pas curry. Le curry s'est déjà produit.
MindJuice
7

Voici un exemple de jouet en Python:

>>> from functools import partial as curry

>>> # Original function taking three parameters:
>>> def display_quote(who, subject, quote):
        print who, 'said regarding', subject + ':'
        print '"' + quote + '"'


>>> display_quote("hoohoo", "functional languages",
           "I like Erlang, not sure yet about Haskell.")
hoohoo said regarding functional languages:
"I like Erlang, not sure yet about Haskell."

>>> # Let's curry the function to get another that always quotes Alex...
>>> am_quote = curry(display_quote, "Alex Martelli")

>>> am_quote("currying", "As usual, wikipedia has a nice summary...")
Alex Martelli said regarding currying:
"As usual, wikipedia has a nice summary..."

(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.

Anon
la source
Je ne comprends pas - vous faites ceci: >>> am_quote = curry (display_quote, "Alex Martelli") mais ensuite vous le faites ensuite: >>> am_quote ("currying", "Comme d'habitude, wikipedia a un joli résumé. .. ") Vous avez donc une fonction avec deux arguments. Il semblerait que le curry devrait vous donner trois fonctions différentes que vous composeriez?
Eric M
J'utilise partiel pour curry un seul paramètre, produisant une fonction avec deux arguments. Si vous le souhaitez, vous pouvez continuer à utiliser am_quote pour en créer un qui ne cite que Alex sur un sujet particulier. L'arrière-plan mathématique peut être axé sur le fait de se retrouver avec des fonctions avec un seul paramètre - mais je crois que la fixation d'un certain nombre de paramètres comme celui-ci est couramment (si ce n'est pas précis du point de vue mathématique) appelée currying.
Anon
(btw - le '>>>' est l'invite de l'interpréteur interactif Python, ne fait pas partie du code.)
Anon
OK merci pour la clarification sur les arguments. Je connais l'invite de l'interpréteur Python, j'essayais de citer les lignes mais cela n'a pas fonctionné ;-)
Eric M
Après votre commentaire, j'ai cherché et trouvé d'autres références, y compris ici sur SO, à la différence entre "currying" et. "application partielle" en réponse à de nombreux cas d'utilisation imprécise que je connais. Voir par exemple: stackoverflow.com/questions/218025/…
Anon
5

Currying traduit une fonction de callable as f(a, b, c)en callable as f(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)

function curry(f) { // curry(f) does the currying transform
  return function(a) {
    return function(b) {
      return f(a, b);
    };
  };
}

// usage
function sum(a, b) {
  return a + b;
}

let carriedSum = curry(sum);

alert( carriedSum(1)(2) ); // 3

Comme vous pouvez le voir, l'implémentation est une série de wrappers.

  • Le résultat curry(func)est un wrapper function(a).
  • Lorsqu'il est appelé comme sum(1), l'argument est enregistré dans l'environnement lexical et un nouveau wrapper est renvoyé function(b).
  • Puis, sum(1)(2)finalement, il function(b)fournit 2 et il passe l'appel à la somme multi-arguments d'origine.
MidhunKrishna
la source
4

Si vous comprenez que partialvous êtes à mi-chemin. L'idée de partialest 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:

(defn add [a b] (+ a b))

Vous savez peut-être que la incfonction ajoute simplement 1 au nombre passé.

(inc 7) # => 8

Construisons-le nous-mêmes en utilisant partial:

(def inc (partial add 1))

Ici, nous renvoyons une autre fonction qui a 1 chargé dans le premier argument de add. Comme addprend deux arguments, la nouvelle incfonction ne veut que l' bargument - pas 2 arguments comme avant car 1 a déjà été partiellement appliqué. C'est donc partialun 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 addvoulait 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éfinir incsans utiliser explicitement partial.

(def inc (add 1)) #partial is implied

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.

Mario
la source
3

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.

James Black
la source
3

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/

times = (x, y) --> x * y
times 2, 3       #=> 6 (normal use works as expected)
double = times 2
double 5         #=> 10

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)

user3804449
la source
3

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:

function curryMinus(x) 
{
  return function(y) 
  {
    return x - y;
  }
}

var minus5 = curryMinus(1);
minus5(3);
minus5(5);

Je peux aussi faire ...

var minus7 = curryMinus(7);
minus7(3);
minus7(5);

C'est très bien pour rendre le code complexe soigné et gérer les méthodes non synchronisées, etc.

Marcus Thornton
la source
2

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:

scala> def plainOldSum(x: Int, y: Int) = x + y
plainOldSum: (x: Int,y: Int)Int
scala> plainOldSum(1, 2)
res4: Int = 3

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:

scala> def curriedSum(x: Int)(y: Int) = x + y
curriedSum: (x: Int)(y: Int)Intscala> second(2)
res6: Int = 3
scala> curriedSum(1)(2)
res5: Int = 3

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é xet renvoie une valeur de fonction pour la deuxième fonction. Cette deuxième fonction prend le paramètre Int y.

Voici une fonction nommée firstqui fait dans l'esprit ce que curriedSumferait la première invocation de fonction traditionnelle :

scala> def first(x: Int) = (y: Int) => x + y
first: (x: Int)(Int) => Int

Appliquer 1 à la première fonction - en d'autres termes, invoquer la première fonction et passer à 1 - donne la deuxième fonction:

scala> val second = first(1)
second: (Int) => Int = <function1>

L'application de 2 à la deuxième fonction donne le résultat:

scala> second(2)
res6: Int = 3
nazar_art
la source
2

Un exemple de curry serait lorsque vous avez des fonctions dont vous ne connaissez actuellement qu'un seul paramètre:

Par exemple:

func aFunction(str: String) {
    let callback = callback(str) // signature now is `NSData -> ()`
    performAsyncRequest(callback)
}

func callback(str: String, data: NSData) {
    // Callback code
}

func performAsyncRequest(callback: NSData -> ()) {
    // Async code that will call callback with NSData as parameter
}

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.

S2dent
la source
se func callbackretourne? Il est appelé @ callback(str)donc let callback = callback(str), le rappel n'est que la valeur de retour defunc callback
nikk wong
non, func callback(_:data:)accepte deux paramètres, ici je ne lui en donne qu'un, le String, donc il attend le suivant ( NSData), c'est pourquoi maintenant let callbackune autre fonction attend que les données soient transmises
S2dent
2

Voici l'exemple de générique et la version la plus courte pour le curry de fonction avec n non. de params.

const add = a => b => b ? add(a + b) : a; 

const add = a => b => b ? add(a + b) : a; 
console.log(add(1)(2)(3)(4)());

Prashant Andani
la source
1

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:

public static class FuncExtensions {
    public static Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(this Func<T1, T2, TResult> func)
    {
        return x1 => x2 => func(x1, x2);
    }
}

//Usage
var add = new Func<int, int, int>((x, y) => x + y).Curry();
var func = add(1);

//Obtaining the next parameter here, calling later the func with next parameter.
//Or you can prepare some base calculations at the previous step and then
//use the result of those calculations when calling the func multiple times 
//with different input parameters.

int result = func(1);
Vadim S.
la source
1

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,

function add(a,b)
    {
        return a+b;
    }
add(5,6);

Ceci est similaire à la fonction de curry suivante,

function add(a)
    {
        return function(b){
            return a+b;
        }
    }
var curryAdd = add(5);
curryAdd(6);

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,

var curryAdd = add(5);

Il vous renverra une fonction comme celle-ci,

curryAdd=function(y){return 5+y;}

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.

curryAdd(6);

qui à son tour résulte,

curryAdd=function(6){return 5+6;}
// Which results in 11

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,

function add(a)
    {
        return function(b){
            return a+b;
        }
    }

Avec l'aide de la fonction flèche, nous pouvons écrire la fonction ci-dessus comme suit,

x=>y=>x+y

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!

sabitha kuppusamy
la source
0

Il existe un exemple de "Currying in ReasonML".

let run = () => {
    Js.log("Curryed function: ");
    let sum = (x, y) => x + y;
    Printf.printf("sum(2, 3) : %d\n", sum(2, 3));
    let per2 = sum(2);
    Printf.printf("per2(3) : %d\n", per2(3));
  };
madeinQuant
la source