J'ai lu plusieurs Java 8 tutoriels auparavant.
À l'heure actuelle, j'ai rencontré le sujet suivant: Est-ce que Java prend en charge le currying?
Ici, je vois le code suivant:
IntFunction<IntUnaryOperator> curriedAdd = a -> b -> a + b;
System.out.println(curriedAdd.apply(1).applyAsInt(12));
Je comprends que cet exemple additionne 2 éléments mais je ne comprends pas la construction:
a -> b -> a + b;
Selon la partie gauche de l'expression, cette ligne devrait implémenter la fonction suivante:
R apply(int value);
Avant cela, je ne rencontrais que des lambdas avec une seule flèche.
Si vous exprimez cela en syntaxe non abrégée lambda ou pre-lambda Java), il est plus clair ce qui se passe ...
La question initiale. Pourquoi deux flèches? Simple, il y a deux fonctions en cours de définition ... La première fonction est une fonction définissant la fonction, la seconde le résultat de cette fonction, qui se trouve être également une fonction. Chacun nécessite un ->
_ opérateur pour le définir.
IntFunction<IntUnaryOperator> curriedAdd = (a) -> {
return (b) -> {
return a + b;
};
};
IntFunction<IntUnaryOperator> curriedAdd = new IntFunction<IntUnaryOperator>() {
@Override
public IntUnaryOperator apply(final int value) {
IntUnaryOperator op = new IntUnaryOperator() {
@Override
public int applyAsInt(int operand) {
return operand + value;
}
};
return op;
}
};
Un IntFunction<R>
est une fonction int -> R
. Un IntUnaryOperator
est une fonction int -> int
.
Ainsi un IntFunction<IntUnaryOperator>
est une fonction qui prend un int
en paramètre et renvoie une fonction qui prend un int
en paramètre et un int
.
a -> b -> a + b;
^ | |
| ---------
| ^
| |
| The IntUnaryOperator (that takes an int, b) and return an int (the sum of a and b)
|
The parameter you give to the IntFunction
Peut-être que c'est plus clair si vous utilisez des classes anonymes pour "décomposer" le lambda:
IntFunction<IntUnaryOperator> add = new IntFunction<IntUnaryOperator>() {
@Override
public IntUnaryOperator apply(int a) {
return new IntUnaryOperator() {
@Override
public int applyAsInt(int b) {
return a + b;
}
};
}
};
Ajouter des parenthèses peut rendre cela plus clair:
IntFunction<IntUnaryOperator> curriedAdd = a -> (b -> (a + b));
Ou probablement une variable intermédiaire peut aider:
IntFunction<IntUnaryOperator> curriedAdd = a -> {
IntUnaryOperator op = b -> a + b;
return op;
};
Réécrivons cette expression lambda avec des parenthèses pour la rendre plus claire:
IntFunction<IntUnaryOperator> curriedAdd = a -> (b -> (a + b));
Nous déclarons donc une fonction prenant un int
qui retourne un Function
. Plus précisément, la fonction retournée prend un int
et retourne un int
(la somme des deux éléments): ceci peut être représenté par un IntUnaryOperator
=.
Par conséquent, curriedAdd
est une fonction prenant un int
et retournant un IntUnaryOperator
, afin qu'il puisse être représenté par IntFunction<IntUnaryOperator>
.
Ce sont deux expressions lambda.
IntFunction<IntUnaryOperator> curriedAdd =
a -> { //this is for the fixed value
return b -> { //this is for the add operation
return a + b;
};
}
IntUnaryOperator addTwo = curriedAdd.apply(2);
System.out.println(addTwo.applyAsInt(12)); //prints 14
Si vous regardez IntFunction
cela pourrait devenir plus clair: IntFunction<R>
Est un FunctionalInterface
. Il représente une fonction qui prend un int
et renvoie une valeur de type R
.
Dans ce cas, le type de retour R
est également un FunctionalInterface
, à savoir un IntUnaryOperator
. Ainsi, la fonction première (externe) renvoie elle-même une fonction.
Dans ce cas: Lorsqu'il est appliqué à un int
, curriedAdd
est censé renvoyer une fonction qui prend à nouveau un int
(et retourne encore int
, car ce que IntUnaryOperator
fait).
En programmation fonctionnelle, il est courant d'écrire le type d'une fonction sous la forme param -> return_value
Et vous voyez exactement cela ici. Donc, le type de curriedAdd
est int -> int -> int
(Ou int -> (int -> int)
si vous préférez).
La syntaxe lambda de Java 8 va dans ce sens. Pour définir une telle fonction, vous écrivez
a -> b -> a + b
ce qui ressemble beaucoup au lambda calcul réel:
λa λb a + b
λb a + b
Est une fonction qui prend un paramètre unique b
et renvoie une valeur (la somme). λa λb a + b
Est une fonction qui accepte un seul paramètre a
et renvoie une autre fonction d'un seul paramètre. λa λb a + b
Renvoie λb a + b
Avec a
défini sur la valeur du paramètre.