De nombreux langages de programmation modernes prennent en charge un certain concept de fermeture , c'est-à-dire d'un morceau de code (un bloc ou une fonction) qui
- Peut être traité comme une valeur, et donc stocké dans une variable, transmis à différentes parties du code, être défini dans une partie d'un programme et appelé dans une partie totalement différente du même programme.
- Peut capturer des variables à partir du contexte dans lequel il est défini et y accéder lors de son invocation ultérieure (éventuellement dans un contexte totalement différent).
Voici un exemple de fermeture écrit en Scala:
def filterList(xs: List[Int], lowerBound: Int): List[Int] =
xs.filter(x => x >= lowerBound)
Le littéral de fonction x => x >= lowerBound
contient la variable libre lowerBound
, qui est fermée (liée) par l'argument de la fonction filterList
qui porte le même nom. La fermeture est transmise à la méthode de bibliothèque filter
, qui peut l'invoquer à plusieurs reprises en tant que fonction normale.
J'ai lu beaucoup de questions et réponses sur ce site et, si je comprends bien, le terme fermeture est souvent automatiquement associé à la programmation fonctionnelle et au style de programmation fonctionnelle.
La définition de la programmation des fonctions sur wikipedia se lit comme suit:
En informatique, la programmation fonctionnelle est un paradigme de programmation qui traite le calcul comme l'évaluation de fonctions mathématiques et évite les données d'état et mutables. Il met l'accent sur l'application des fonctions, contrairement au style de programmation impératif, qui met l'accent sur les changements d'état.
et plus loin
[...] dans le code fonctionnel, la valeur de sortie d'une fonction dépend uniquement des arguments qui sont entrés dans la fonction [...]. L'élimination des effets secondaires peut faciliter la compréhension et la prévision du comportement d'un programme, ce qui est l'une des principales motivations pour le développement d'une programmation fonctionnelle.
D'un autre côté, de nombreuses constructions de fermeture fournies par les langages de programmation permettent à une fermeture de capturer des variables non locales et de les modifier lorsque la fermeture est invoquée, produisant ainsi un effet secondaire sur l'environnement dans lequel elles ont été définies.
Dans ce cas, les fermetures implémentent la première idée de programmation fonctionnelle (les fonctions sont des entités de première classe qui peuvent être déplacées comme les autres valeurs) mais négligent la deuxième idée (en évitant les effets secondaires).
Cette utilisation des fermetures avec effets secondaires est-elle considérée comme un style fonctionnel ou les fermetures sont-elles considérées comme une construction plus générale qui peut être utilisée à la fois pour un style de programmation fonctionnel et non fonctionnel? Existe-t-il de la littérature sur ce sujet?
NOTE IMPORTANTE
Je ne remets pas en question l'utilité des effets secondaires ou des fermetures avec effets secondaires. De plus, je ne suis pas intéressé par une discussion sur les avantages / inconvénients des fermetures avec ou sans effets secondaires.
Je suis seulement intéressé de savoir si l'utilisation de telles fermetures est toujours considérée comme un style fonctionnel par le promoteur de la programmation fonctionnelle ou si, au contraire, leur utilisation est déconseillée lors de l'utilisation d'un style fonctionnel.
la source
Réponses:
Non; la définition du paradigme fonctionnel concerne le manque d'état et implicitement le manque d'effets secondaires. Il ne s'agit pas de fonctions de haut niveau, de fermetures, de manipulation de liste prise en charge par la langue ou d'autres fonctionnalités de langage ...
Le nom de la programmation fonctionnelle vient de la notion mathématique de fonctions - des appels répétés sur la même entrée donnent toujours la même sortie - fonction nullipotente. Cela ne peut être réalisé que si les données sont immuables . Afin de faciliter le développement, les fonctions sont devenues mutables (les fonctions changent, les données sont toujours immuables) et donc la notion de fonctions d'ordre supérieur (fonctionnelles en mathématiques, comme dérivées par exemple) - une fonction qui prend en entrée une autre fonction. Pour la possibilité de transporter des fonctions et de les passer comme arguments, des fonctions de première classe ont été adoptées; après cela, pour améliorer encore la productivité, des fermetures sont apparues.
C'est, bien sûr, une vue très simplifiée.
la source
map
, par exemple, qui prend une fonction, l'applique à une liste et renvoie une liste des résultats.map
ne modifie aucun de ses arguments, il ne change pas le comportement de la fonction qu'il prend comme argument, mais c'est définitivement une fonction d'ordre supérieur - si vous l'appliquez partiellement, avec juste le paramètre de fonction, vous avez construit un nouvelle fonction qui fonctionne sur une liste, mais toujours aucune mutation n'est survenue.Non. Le "style fonctionnel" implique une programmation sans effet secondaire.
Pour voir pourquoi, jetez un œil à l'entrée de blog d'Eric Lippert sur la
ForEach<T>
méthode d'extension, et pourquoi Microsoft n'a pas inclus une méthode de séquence comme celle-ci dans Linq :la source
ParallelQuery<T>.ForAll(...)
. L'implémentation d'un telIEnumerable<T>.ForEach(...)
est extrêmement utile pour le débogage desForAll
instructions (remplacez leForAll
parForEach
et supprimez leAsParallel()
et vous pouvez beaucoup plus facilement le parcourir / le déboguer)La programmation fonctionnelle fait certes passer les fonctions de première classe au niveau conceptuel suivant, mais déclarer des fonctions anonymes ou passer des fonctions à d'autres fonctions n'est pas nécessairement une chose de programmation fonctionnelle. En C, tout était un entier. Un nombre, un pointeur sur les données, un pointeur sur une fonction ... tout simplement des entiers. Vous pouvez passer des pointeurs de fonction à d'autres fonctions, faire des listes de pointeurs de fonction ... Heck, si vous travaillez en langage assembleur, les fonctions ne sont vraiment que des adresses en mémoire où sont stockés des blocs d'instructions machine. Donner un nom à une fonction est une surcharge supplémentaire pour les personnes qui ont besoin d'un compilateur pour écrire du code. Les fonctions étaient donc «de première classe» dans ce sens dans un langage complètement non fonctionnel.
Si la seule chose que vous faites est de calculer des formules mathématiques dans un REPL, alors vous pouvez être fonctionnellement pur avec votre langage. Mais la plupart des programmes d'entreprise ont des effets secondaires. Perdre de l'argent en attendant la fin d'un programme de longue durée est un effet secondaire. Toute action externe: écrire dans un fichier, mettre à jour une base de données, consigner les événements dans l'ordre, etc. nécessite un changement d'état. Nous pourrions débattre de la question de savoir si l'état est vraiment changé si vous encapsulez ces actions dans des wrappers immuables qui repoussent les effets secondaires afin que votre code n'ait pas à s'en soucier. Mais c'est comme discuter si un arbre fait du bruit s'il tombe dans la forêt sans que personne ne l'entende. Le fait est que l'arbre a commencé en position verticale et s'est retrouvé au sol. L'état est changé lorsque les choses sont faites, ne serait-ce que pour signaler que les choses ont été faites.
Il nous reste donc une échelle de pureté fonctionnelle, pas du noir et du blanc, mais des nuances de gris. Et à cette échelle, moins il y a d'effets secondaires, moins il y a de mutabilité, mieux c'est (plus fonctionnel).
Si vous avez absolument besoin d'un effet secondaire ou d'un état mutable dans votre code par ailleurs fonctionnel, vous vous efforcez de l'encapsuler ou de le faire du reste de votre programme du mieux que vous le pouvez. L'utilisation d'une fermeture (ou de toute autre chose) pour injecter des effets secondaires ou un état mutable dans des fonctions par ailleurs pures est l'antithèse de la programmation fonctionnelle. La seule exception pourrait être si la fermeture était le moyen le plus efficace pour encapsuler les effets secondaires du code auquel elle est transmise. Ce n'est toujours pas de la «programmation fonctionnelle», mais c'est peut-être le placard que vous pouvez obtenir dans certaines situations.
la source