Quelle est la différence entre le curry et l'application partielle?


438

Je vois assez souvent sur Internet diverses plaintes selon lesquelles les exemples de curry d'autres personnes ne sont pas du curry, mais ne sont en fait qu'une application partielle.

Je n'ai pas trouvé d'explication décente de ce qu'est une application partielle, ni en quoi elle diffère du curry. Il semble y avoir une confusion générale, des exemples équivalents étant décrits comme le curry dans certains endroits et une application partielle dans d'autres.

Quelqu'un pourrait-il me donner une définition des deux termes et des détails sur la façon dont ils diffèrent?

Réponses:


256

Currying consiste à convertir une seule fonction de n arguments en n fonctions avec un seul argument chacune. Étant donné la fonction suivante:

function f(x,y,z) { z(x(y));}

Au curry, devient:

function f(x) { lambda(y) { lambda(z) { z(x(y)); } } }

Pour obtenir l'application complète de f (x, y, z), vous devez procéder comme suit:

f(x)(y)(z);

De nombreux langages fonctionnels vous permettent d'écrire f x y z. Si vous appelez uniquement f x you f (x) (y), vous obtenez une fonction partiellement appliquée - la valeur de retour est une fermeture de lambda(z){z(x(y))}avec les valeurs transmises de x et y à f(x,y).

Une façon d'utiliser l'application partielle consiste à définir les fonctions comme des applications partielles de fonctions généralisées, comme fold :

function fold(combineFunction, accumulator, list) {/* ... */}
function sum     = curry(fold)(lambda(accum,e){e+accum}))(0);
function length  = curry(fold)(lambda(accum,_){1+accum})(empty-list);
function reverse = curry(fold)(lambda(accum,e){concat(e,accum)})(empty-list);

/* ... */
@list = [1, 2, 3, 4]
sum(list) //returns 10
@f = fold(lambda(accum,e){e+accum}) //f = lambda(accumulator,list) {/*...*/}
f(0,list) //returns 10
@g = f(0) //same as sum
g(list)  //returns 10

40
Vous dites que l'application partielle consiste à utiliser une fonction et à en utiliser certaines, mais pas toutes les fonctions résultantes?
SpoonMeiser

9
plus ou moins, oui. Si vous ne fournissez qu'un sous-ensemble des arguments, vous récupérerez une fonction qui accepte le reste des arguments
Mark Cidade

1
Est-ce que changer une fonction f (a, b, c, d) en g (a, b) compterait comme une application partielle? Ou est-ce uniquement lorsqu'il est appliqué à des fonctions curry? Désolé d'être une douleur, mais je cherche une réponse explicite ici.
SpoonMeiser

2
@Mark: Je suppose que ce n'est qu'un de ces concepts qui fait ressortir le pédant en moi - mais un appel à des sources faisant autorité ne satisfait guère, car ils semblent tous pointer l'un vers l'autre. Wikipédia n'est guère ce que je considère comme une source faisant autorité, mais je comprends qu'il est difficile de trouver autre chose. Qu'il suffise de dire que je pense que nous savons tous les deux ce dont nous parlons et la puissance de celui-ci, que nous puissions ou non être d'accord (ou pas d'accord) sur les particularités de la langue vernaculaire! :) Merci Mark!
Jason Bunting

5
@JasonBunting, Concernant votre premier commentaire, ce dont vous parliez est décourageant . Currying prend une fonction multi-arg en entrée et retourne une chaîne de fonctions 1-arg en sortie. Le décorticage prend une chaîne de fonctions 1-arg en entrée et retourne une fonction multi-arg en sortie. Tel qu'élaboré sur stackoverflow.com/a/23438430/632951
Pacerier

165

La façon la plus simple de voir comment ils diffèrent est de considérer un exemple réel . Supposons que nous ayons une fonction Addqui prend 2 nombres en entrée et renvoie un nombre en sortie, par exemple les Add(7, 5)retours 12. Dans ce cas:

  • L'application partielle de la fonction Addavec une valeur 7nous donnera une nouvelle fonction en sortie. Cette fonction elle-même prend 1 nombre en entrée et produit un nombre. En tant que tel:

    Partial(Add, 7); // returns a function f2 as output
    
                     // f2 takes 1 number as input and returns a number as output
    

    Nous pouvons donc le faire:

    f2 = Partial(Add, 7);
    f2(5); // returns 12;
           // f2(7)(5) is just a syntactic shortcut
    
  • Currying la fonction Addnous donnera une nouvelle fonction en sortie. Cette fonction elle-même prend 1 numéro en entrée et génère une autre nouvelle fonction. Cette troisième fonction prend alors 1 nombre en entrée et renvoie un nombre en sortie. En tant que tel:

    Curry(Add); // returns a function f2 as output
    
                // f2 takes 1 number as input and returns a function f3 as output
                // i.e. f2(number) = f3
    
                // f3 takes 1 number as input and returns a number as output
                // i.e. f3(number) = number
    

    Nous pouvons donc le faire:

    f2 = Curry(Add);
    f3 = f2(7);
    f3(5); // returns 12
    

En d'autres termes, "currying" et "partial application" sont deux fonctions totalement différentes. Le curry prend exactement 1 entrée, tandis que l'application partielle prend 2 (ou plus) entrées.

Même si elles renvoient toutes deux une fonction en sortie, les fonctions renvoyées sont de formes totalement différentes, comme illustré ci-dessus.


25
Une application partielle transforme une fonction de n-aryen (x - n)-ary, currying de n-aryen n * 1-ary. Une fonction partiellement appliquée a une portée réduite (d'application), c'est-à-dire qu'elle Add7est moins expressive que Add. En revanche, une fonction au curry est aussi expressive que la fonction d'origine.
bob

4
Je crois que le trait le plus distinctif est lorsque nous curry f (x, y, z) => R, nous obtenons f (x) qui renvoie g (y) => h (z) => R, chacun consommant un seul argument; mais lorsque nous appliquons partiellement f (x, y, z) comme f (x), nous obtenons g (y, z) => R, c'est-à-dire avec deux arguments. Sinon pour ce trait, nous pourrions dire que le curry est comme une application partielle à 0 arguments, laissant ainsi tous les arguments non liés; cependant en réalité f () partiellement appliqué à 0 arguments est une fonction consommant 3 arguments à la fois, contrairement à f () au curry.
Maksim Gumerov, le

2
Encore une fois, la bonne réponse n'est pas la première ou la plus votée: la simple explication de la signature du curry vs partielle à la fin de cette réponse est vraiment le moyen le plus simple de résoudre la question.
fnl

2
Que signifie le commentaire f2(7)(5) is just a syntactic shortcut? (Je sais très peu.) Ne f2contient pas déjà / "savoir" 7?
Zach Mierzejewski

@Pacerier, y a-t-il une curryimplémentation quelque part (ne pense pas qu'elle soit dedans functools)
alancalvitti

51

Remarque: cela a été tiré de F # Basics, un excellent article d'introduction pour les développeurs .NET qui se lancent dans la programmation fonctionnelle.

Currying signifie casser une fonction avec de nombreux arguments en une série de fonctions qui prennent chacune un argument et produisent finalement le même résultat que la fonction d'origine. Le curry est probablement le sujet le plus difficile pour les développeurs débutants en programmation fonctionnelle, en particulier parce qu'il est souvent confondu avec une application partielle. Vous pouvez voir les deux à l'œuvre dans cet exemple:

let multiply x y = x * y    
let double = multiply 2
let ten = double 5

Tout de suite, vous devriez voir un comportement différent de la plupart des langues impératives. La deuxième instruction crée une nouvelle fonction appelée double en passant un argument à une fonction qui en prend deux. Le résultat est une fonction qui accepte un argument int et produit la même sortie que si vous aviez appelé multiplier avec x égal à 2 et y égal à cet argument. En termes de comportement, c'est la même chose que ce code:

let double2 z = multiply 2 z

Souvent, les gens disent à tort que multiplier est curry pour former double. Mais ce n'est que quelque peu vrai. La fonction multiplier est curry, mais cela se produit lorsqu'elle est définie car les fonctions en F # sont curry par défaut. Lorsque la fonction double est créée, il est plus précis de dire que la fonction multiplier est partiellement appliquée.

La fonction multiplier est en réalité une série de deux fonctions. La première fonction prend un argument int et renvoie une autre fonction, liant effectivement x à une valeur spécifique. Cette fonction accepte également un argument int que vous pouvez considérer comme la valeur à lier à y. Après avoir appelé cette deuxième fonction, x et y sont tous deux liés, donc le résultat est le produit de x et y tel que défini dans le corps de double.

Pour créer un double, la première fonction de la chaîne de fonctions de multiplication est évaluée pour appliquer partiellement la multiplication. La fonction résultante porte le nom double. Lorsque le double est évalué, il utilise son argument avec la valeur partiellement appliquée pour créer le résultat.


33

Question interessante. Après un peu de recherche, «l'application de fonction partielle ne curry pas» a donné la meilleure explication que j'ai trouvée. Je ne peux pas dire que la différence pratique est particulièrement évidente pour moi, mais je ne suis pas un expert en PF ...

Une autre page intéressante (que j'avoue n'avoir pas encore entièrement lue) est "Currying and Partial Application with Java Closures" .

Il semble que ce soit une paire de termes largement confuse, rappelez-vous.


5
Le premier lien est clair sur les différences. En voici une autre que j'ai trouvée utile: bit.ly/CurryingVersusPartialApplication
Jason Bunting

5
Le currying est lié aux tuples (transformer une fonction qui prend un argument de tuple en une fonction qui prend n arguments séparés, et vice versa). Une application partielle est la possibilité d'appliquer une fonction à certains arguments, produisant une nouvelle fonction pour les arguments restants. Il est facile de se souvenir si vous pensez simplement au curry == à voir avec les tuples.
Don Stewart

9
Les liens @Jon que vous avez publiés sont informatifs, mais il sera préférable d'élargir votre réponse et d'ajouter plus d'informations ici.
Zaheer Ahmed


11
Je ne peux pas croire que vous ayez 20 votes positifs pour quelques liens et une admission que vous ne connaissez pas vraiment la différence entre le curry et l'application partielle. Bien joué, monsieur.
AlienWebguy

16

J'ai répondu à cela dans un autre fil https://stackoverflow.com/a/12846865/1685865 . En bref, l'application d'une fonction partielle consiste à corriger certains arguments d'une fonction multivariable donnée pour produire une autre fonction avec moins d'arguments, tandis que Currying consiste à transformer une fonction de N arguments en une fonction unaire qui renvoie une fonction unaire ... [Un exemple de Le curry est montré à la fin de ce post.]

Le curry est principalement d'intérêt théorique: on peut exprimer des calculs en utilisant uniquement des fonctions unaires (c'est-à-dire que chaque fonction est unaire). En pratique et en tant que sous-produit, c'est une technique qui peut rendre triviales de nombreuses applications fonctionnelles partielles utiles (mais pas toutes), si le langage a des fonctions curry. Encore une fois, ce n'est pas le seul moyen de mettre en œuvre des applications partielles. Vous pouvez donc rencontrer des scénarios où une application partielle est effectuée d'une autre manière, mais les gens la confondent avec Currying.

(Exemple de curry)

En pratique, on n’écrirait pas

lambda x: lambda y: lambda z: x + y + z

ou le javascript équivalent

function (x) { return function (y){ return function (z){ return x + y + z }}}

au lieu de

lambda x, y, z: x + y + z

pour le plaisir de Currying.


1
Diriez-vous que le curry est un cas spécifique d'application partielle?
SpoonMeiser

1
@SpoonMeiser, Non, le curry n'est pas un cas spécifique d'application partielle: une application partielle d'une fonction à 2 entrées n'est pas la même chose que le curry de la fonction. Voir stackoverflow.com/a/23438430/632951 .
Pacerier

10

Le curry est une fonction d' un argument qui prend une fonction fet renvoie une nouvelle fonction h. Notez que hprend un argument de Xet renvoie une fonction qui correspond Yà Z:

curry(f) = h 
f: (X x Y) -> Z 
h: X -> (Y -> Z)

Une application partielle est une fonction de deux (ou plus) arguments qui prend une fonction fet un ou plusieurs arguments supplémentaires fet renvoie une nouvelle fonction g:

part(f, 2) = g
f: (X x Y) -> Z 
g: Y -> Z

La confusion survient car avec une fonction à deux arguments, l'égalité suivante est vérifiée:

partial(f, a) = curry(f)(a)

Les deux côtés produiront la même fonction à un argument.

L'égalité n'est pas vraie pour les fonctions d'arité supérieure, car dans ce cas, le curry renvoie une fonction à un argument, tandis que l'application partielle renvoie une fonction à plusieurs arguments.

La différence réside également dans le comportement, alors que le curry transforme récursivement toute la fonction d'origine (une fois pour chaque argument), l'application partielle n'est qu'un remplacement en une étape.

Source: Wikipedia Currying .


8

La différence entre le curry et l'application partielle peut être mieux illustrée par cet exemple JavaScript suivant:

function f(x, y, z) {
    return x + y + z;
}

var partial = f.bind(null, 1);

6 === partial(2, 3);

Une application partielle se traduit par une fonction d'arité plus petite; dans l'exemple ci-dessus, fa une arité de 3 alors qu'elle partialn'a qu'une arité de 2. Plus important encore, une fonction partiellement appliquée retournerait immédiatement le résultat lors de son appel , pas une autre fonction le long de la chaîne de curry. Donc, si vous voyez quelque chose comme partial(2)(3)ça, ce n'est pas une application partielle en réalité.

Lectures complémentaires:


"une fonction partiellement appliquée retournerait immédiatement le résultat lors de son appel" - ce n'est pas correct, n'est-ce pas? lorsque j'applique partiellement une fonction, cette expression renvoie une fonction, pas "un résultat". Ok, vous vouliez probablement dire que cette dernière fonction, lorsqu'elle est appelée avec les arguments restants, renvoie le résultat, contrairement à creuser une étape plus bas dans le curry. Mais personne ne dit réellement que vous devez spécifier tous les arguments restants: vous pouvez appliquer partiellement le résultat d'une application partielle, et ce sera à nouveau une fonction, pas un "résultat"
Maksim Gumerov

6

Réponse simple

Curry: permet d'appeler une fonction, de la diviser en plusieurs appels, en fournissant un argument par appel.

Partiel: permet d'appeler une fonction, de la diviser en plusieurs appels et de fournir plusieurs arguments par appel.


Conseils simples

Les deux vous permettent d'appeler une fonction fournissant moins d'arguments (ou, mieux, les fournissant cumulativement). En fait, les deux lient (à chaque appel) une valeur spécifique à des arguments spécifiques de la fonction.

La vraie différence est visible lorsque la fonction a plus de 2 arguments.


Simple e (c) (exemple)

(en Javascript)

function process(context, success_callback, error_callback, subject) {...}

pourquoi toujours passer les arguments, comme le contexte et les rappels, s'ils seront toujours les mêmes? Liez juste quelques valeurs pour la fonction

processSubject = _.partial(process, my_context, my_success, my_error)

et l'appeler sur subject1 et foobar avec

processSubject('subject1');
processSubject('foobar');

Confortable, n'est-ce pas? 😉

Avec le curry, vous devez passer un argument à la fois

curriedProcess = _.curry(process);
processWithBoundedContext = curriedProcess(my_context);
processWithCallbacks = processWithBoundedContext(my_success)(my_error); // note: these are two sequential calls

result1 = processWithCallbacks('subject1');
// same as: process(my_context, my_success, my_error, 'subject1');
result2 = processWithCallbacks('foobar'); 
// same as: process(my_context, my_success, my_error, 'foobar');

Avertissement

J'ai sauté toutes les explications académiques / mathématiques. Parce que je ne le sais pas. Peut-être que cela a aidé 🙃


4

J'ai beaucoup posé cette question en apprenant et on m'a depuis posé de nombreuses fois. La façon la plus simple de décrire la différence est que les deux sont les mêmes :) Laissez-moi vous expliquer ... il y a évidemment des différences.

L'application partielle et le curry impliquent de fournir des arguments à une fonction, peut-être pas tous en même temps. Un exemple assez canonique est d'ajouter deux nombres. En pseudocode (en fait JS sans mots-clés), la fonction de base peut être la suivante:

add = (x, y) => x + y

Si je voulais une fonction "addOne", je pourrais l'appliquer partiellement ou la curry:

addOneC = curry(add, 1)
addOneP = partial(add, 1)

Maintenant, les utiliser est clair:

addOneC(2) #=> 3
addOneP(2) #=> 3

Alors quelle est la différence? Eh bien, c'est subtil, mais une application partielle implique de fournir des arguments et la fonction retournée exécutera ensuite la fonction principale lors de la prochaine invocation tandis que le curry continuera d'attendre jusqu'à ce qu'il ait tous les arguments nécessaires:

curriedAdd = curry(add) # notice, no args are provided
addOne = curriedAdd(1) # returns a function that can be used to provide the last argument
addOne(2) #=> returns 3, as we want

partialAdd = partial(add) # no args provided, but this still returns a function
addOne = partialAdd(1) # oops! can only use a partially applied function once, so now we're trying to add one to an undefined value (no second argument), and we get an error

En bref, utilisez une application partielle pour préremplir certaines valeurs, sachant que la prochaine fois que vous appellerez la méthode, elle s'exécutera, laissant non défini tous les arguments non fournis; utilisez le curry lorsque vous souhaitez renvoyer continuellement une fonction partiellement appliquée autant de fois que nécessaire pour remplir la signature de la fonction. Un dernier exemple artificiel:

curriedAdd = curry(add)
curriedAdd()()()()()(1)(2) # ugly and dumb, but it works

partialAdd = partial(add)
partialAdd()()()()()(1)(2) # second invocation of those 7 calls fires it off with undefined parameters

J'espère que cela t'aides!

MISE À JOUR: Certains langages ou implémentations lib vous permettront de passer une arité (nombre total d'arguments en évaluation finale) à l'implémentation d'application partielle qui peut confondre mes deux descriptions dans un désordre déroutant ... mais à ce stade, les deux techniques sont largement interchangeable.


3

Pour moi, une application partielle doit créer une nouvelle fonction où les arguments utilisés sont complètement intégrés dans la fonction résultante.

La plupart des langages fonctionnels implémentent le curry en renvoyant une fermeture: ne pas évaluer sous lambda lorsqu'il est partiellement appliqué. Donc, pour que l'application partielle soit intéressante, nous devons faire la différence entre le curry et l'application partielle et considérer l'application partielle comme le curry plus l'évaluation sous lambda.


3

Je pourrais me tromper ici, car je n'ai pas une solide formation en mathématiques théoriques ou en programmation fonctionnelle, mais de ma brève incursion en FP, il semble que le curry a tendance à transformer une fonction de N arguments en N fonctions d'un argument, tandis que l'application partielle [en pratique] fonctionne mieux avec des fonctions variadiques avec un nombre indéterminé d'arguments. Je sais que certains des exemples des réponses précédentes défient cette explication, mais cela m'a le plus aidé à séparer les concepts. Considérez cet exemple (écrit en CoffeeScript pour la concision, mes excuses si cela prête à confusion, mais veuillez demander des éclaircissements, si nécessaire):

# partial application
partial_apply = (func) ->
  args = [].slice.call arguments, 1
  -> func.apply null, args.concat [].slice.call arguments

sum_variadic = -> [].reduce.call arguments, (acc, num) -> acc + num

add_to_7_and_5 = partial_apply sum_variadic, 7, 5

add_to_7_and_5 10 # returns 22
add_to_7_and_5 10, 11, 12 # returns 45

# currying
curry = (func) ->
  num_args = func.length
  helper = (prev) ->
    ->
      args = prev.concat [].slice.call arguments
      return if args.length < num_args then helper args else func.apply null, args
  helper []

sum_of_three = (x, y, z) -> x + y + z
curried_sum_of_three = curry sum_of_three
curried_sum_of_three 4 # returns a function expecting more arguments
curried_sum_of_three(4)(5) # still returns a function expecting more arguments
curried_sum_of_three(4)(5)(6) # returns 15
curried_sum_of_three 4, 5, 6 # returns 15

C'est évidemment un exemple artificiel, mais notez que l'application partielle d'une fonction qui accepte n'importe quel nombre d'arguments nous permet d'exécuter une fonction mais avec quelques données préliminaires. Curryer une fonction est similaire mais nous permet d'exécuter une fonction à N paramètres en morceaux jusqu'à ce que, mais seulement jusqu'à, tous les N paramètres soient pris en compte.

Encore une fois, c'est mon point de vue sur les choses que j'ai lues. Si quelqu'un n'est pas d'accord, j'apprécierais un commentaire sur la raison plutôt qu'une baisse immédiate. De plus, si le CoffeeScript est difficile à lire, veuillez visiter coffeescript.org, cliquez sur "essayer coffeescript" et collez mon code pour voir la version compilée, qui peut (espérons-le) avoir plus de sens. Merci!


2

Je vais supposer que la plupart des gens qui posent cette question connaissent déjà les concepts de base, il n'est donc pas nécessaire d'en parler. C'est le chevauchement qui est la partie déroutante.

Vous pourrez peut-être utiliser pleinement les concepts, mais vous les comprenez ensemble comme ce flou conceptuel amorphe pseudo-atomique. Ce qui manque, c'est de savoir où se situe la frontière entre eux.

Au lieu de définir ce que chacun est, il est plus facile de souligner uniquement leurs différences - la frontière.

Le curry est lorsque vous définissez la fonction.

L'application partielle est lorsque vous appelez la fonction.

L'application est mathématique pour appeler une fonction.

Une application partielle nécessite d'appeler une fonction curry et d'obtenir une fonction comme type de retour.


1

Il y a d'autres bonnes réponses ici, mais je crois que cet exemple (selon ma compréhension) en Java pourrait être bénéfique pour certaines personnes:

public static <A,B,X> Function< B, X > partiallyApply( BiFunction< A, B, X > aBiFunction, A aValue ){
    return b -> aBiFunction.apply( aValue, b );
}

public static <A,X> Supplier< X > partiallyApply( Function< A, X > aFunction, A aValue ){
    return () -> aFunction.apply( aValue );
}

public static <A,B,X> Function<  A, Function< B, X >  > curry( BiFunction< A, B, X > bif ){
    return a -> partiallyApply( bif, a );
}

Le currying vous donne donc une fonction à un argument pour créer des fonctions, où application partielle crée une fonction wrapper qui code en dur un ou plusieurs arguments.

Si vous souhaitez copier et coller, les éléments suivants sont plus bruyants mais plus conviviaux, car les types sont plus indulgents:

public static <A,B,X> Function< ? super B, ? extends X > partiallyApply( final BiFunction< ? super A, ? super B, X > aBiFunction, final A aValue ){
    return b -> aBiFunction.apply( aValue, b );
}

public static <A,X> Supplier< ? extends X > partiallyApply( final Function< ? super A, X > aFunction, final A aValue ){
    return () -> aFunction.apply( aValue );
}

public static <A,B,X> Function<  ? super A,  Function< ? super B, ? extends X >  > curry( final BiFunction< ? super A, ? super B, ? extends X > bif ){
    return a -> partiallyApply( bif, a );
}

Ce qui suit m'a donné un aperçu clé: "Donc, le currying vous donne une fonction à un argument pour créer des fonctions, où partial-application crée une fonction wrapper qui code en dur un ou plusieurs arguments."
Roland

0

En écrivant ceci, j'ai confondu le curry et le non curry. Ce sont des transformations inverses sur les fonctions. Peu importe ce que vous appelez, tant que vous obtenez ce que la transformation et son inverse représentent.

Le non-currying n'est pas défini très clairement (ou plutôt, il existe des définitions «conflictuelles» qui captent toutes l'esprit de l'idée). Fondamentalement, cela signifie transformer une fonction qui prend plusieurs arguments en une fonction qui prend un seul argument. Par exemple,

(+) :: Int -> Int -> Int

Maintenant, comment transformez-vous cela en une fonction qui prend un seul argument? Vous trichez, bien sûr!

plus :: (Int, Int) -> Int

Notez que plus prend désormais un seul argument (qui est composé de deux choses). Super!

À quoi ça sert? Eh bien, si vous avez une fonction qui prend deux arguments et que vous avez une paire d'arguments, il est bon de savoir que vous pouvez appliquer la fonction aux arguments et toujours obtenir ce que vous attendez. Et, en fait, la plomberie pour le faire existe déjà, de sorte que vous n'avez pas à faire des choses comme la correspondance explicite de motifs. Tout ce que tu dois faire est:

(uncurry (+)) (1,2)

Alors, quelle est l'application de fonction partielle? C'est une manière différente de transformer une fonction en deux arguments en une fonction avec un seul argument. Cela fonctionne cependant différemment. Encore une fois, prenons (+) comme exemple. Comment pourrions-nous en faire une fonction qui prend un seul Int comme argument? On triche!

((+) 0) :: Int -> Int

C'est la fonction qui ajoute zéro à tout Int.

((+) 1) :: Int -> Int

ajoute 1 à tout Int. Etc. Dans chacun de ces cas, (+) est "partiellement appliqué".

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.