Ce n'est pas f(a)(b)(c)
mais plutôt curry(f)(a)(b)(c)
. Nous emballons f
de telle sorte que chaque argument supplémentaire renvoie soit un autre curry
ou invoque effectivement la fonction avec empressement. C'est C++17, mais peut être implémenté en C++11 avec un tas de travail supplémentaire.
Notez qu'il s'agit d'une solution pour faire un curry d'une fonction - ce qui est l'impression que j'ai eue de la question - et non d'une solution pour replier une fonction binaire.
template <class F>
auto curry(F f) {
return [f](auto... args) -> decltype(auto) {
if constexpr(std::is_invocable<F&, decltype(args)...>{}) {
return std::invoke(f, args...);
}
else {
return curry([=](auto... new_args)
-> decltype(std::invoke(f, args..., new_args...))
{
return std::invoke(f, args..., new_args...);
});
}
};
}
J'ai sauté les références de transmission pour plus de concision. Un exemple d'utilisation serait :
int add(int a, int b, int c) { return a+b+c; }
curry(add)(1,2,2); // 5
curry(add)(1)(2)(2); // also 5
curry(add)(1, 2)(2); // still the 5th
curry(add)()()(1,2,2); // FIVE
auto f = curry(add)(1,2);
f(2); // i plead the 5th
38 votes
Puis-je vous demander pourquoi exactement vous essayez de faire de la programmation fonctionnelle en c++ (par opposition à tout autre langage intrinsèquement fonctionnel) ?
12 votes
Je ne sais pas si vous pouvez le faire avec juste
f(a)(b)(c)
. Vous devriez être capable de le faire fonctionner assez facilement si vous voulez utiliserf(a)(b)(c)()
.2 votes
@BenSteffan Je pratique le C++ ces derniers temps et je souhaite approfondir au maximum le langage et ses bibliothèques, et j'ai voulu essayer la bibliothèque fonctionnelle. J'ai implémenté la fonction f(a)(b) facilement, mais je n'arrive pas à comprendre comment implémenter f(a)(b)(c), et je ne veux pas aller plus loin avant d'avoir trouvé la solution xD
1 votes
@NathanOliver Je pense que je saurais comment implémenter f(a)(b)(c)(), mais je veux que cela fonctionne pour f(a)(b)(c) :(
6 votes
@BenSteffan Le C++ proposait des objets fonctionnels avant que certains des langages fonctionnels grand public ne voient le jour. Les itérateurs et les algorithmes ne sont qu'une des caractéristiques qui ont été transférées du C++ aux langages fonctionnels. Il déjà supporte les lambdas. Il déjà permet de passer des fonctions comme arguments aux itérateurs. etc etc etc
1 votes
@Gigaxel Pouvez-vous expliquer ce que vous avez fait, c'est-à-dire ce que fait
[a]
?7 votes
@am.rez c'est le liste de capture de l'expression lambda .
6 votes
@am.rez Il permet à la fonction lambda d'utiliser le paramètre de la fonction plus2 dans son corps.
9 votes
Notez que vous pouvez utiliser
auto
pour le type de retour de votre fonction, et éviter le coût de l'effacement de type destd::function
.1 votes
@Quentin Oui, je suis conscient de cela, mais je voulais rendre plus clair le type de retour. J'aurais pu résoudre le problème si j'avais utilisé auto pour le type de retour, car j'implémentais la fonction correctement, mais le type de retour n'était pas correct. Merci pour ces conseils supplémentaires :D
2 votes
Personnellement, je pense que la meilleure façon de comprendre les aspects fonctionnels du C++ est d'apprendre d'abord un langage fonctionnel, puis de revenir au C++, car cela vous donne un meilleur aperçu du monde sans classe dont sont issues les expressions lambda.
1 votes
@Pharap Je suis d'accord. Je pense que le but d'apprendre un langage fonctionnel est d'apprendre à penser le calcul différemment. Personnellement, j'aime Scheme parce qu'il est facile à apprendre et qu'il vous récompense lorsque vous le faites d'une manière fonctionnelle (code plus propre). Bien sûr, Haskell (et ML) est également très bon (et populaire) mais je le trouve légèrement plus difficile et je suis toujours en train de l'apprendre.
4 votes
OP - Le but est-il de pliage une fonction binaire
f
ou à curry une fonction arbitrairef
?2 votes
@AlexVong J'ai choisi d'apprendre Haskell comme premier langage fonctionnel parce qu'il existe un très beau tutoriel intitulé Apprenez vous un Haskell pour le bien de tous '. Ce n'est pas suffisant pour maîtriser le langage, mais c'est un bon point de départ qui rend la courbe d'apprentissage moins raide.
1 votes
@Pharap Merci de partager cette ressource. Je vais certainement me pencher sur Haskell dans un avenir proche :D
1 votes
@Pharap Peut confirmer que le livre est étonnant pour un débutant, et ce qui est encore plus étonnant, c'est qu'au moment de sa rédaction, l'auteur était étudiant (en Slovénie) !
1 votes
@BenSteffan : Le PO veut clairement améliorer sa connaissance du C++ en tentant cet exercice. C'est une excellente idée !
0 votes
@TomSwirly Je ne voulais pas critiquer le PO, c'est juste que l'idée m'a paru étrange, d'où ma question.
0 votes
@BenSteffan Ce n'est pas étrange si vous le regardez du point de vue d'un débutant. Parfois, la meilleure façon d'apprendre comment quelque chose fonctionne est d'en abuser jusqu'à ce qu'il soit cassé, après quoi il deviendra évident pourquoi c'est une mauvaise idée et pourquoi les gens ne le font pas.