J'ai vraiment du mal à comprendre la différence entre les paradigmes de programmation procédurale et fonctionnelle .
Voici les deux premiers paragraphes de l'entrée Wikipedia sur la programmation fonctionnelle :
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. La programmation fonctionnelle a ses racines dans le calcul lambda, un système formel développé dans les années 1930 pour étudier la définition de fonction, l'application de fonction et la récursivité. De nombreux langages de programmation fonctionnels peuvent être considérés comme des élaborations sur le calcul lambda.
En pratique, la différence entre une fonction mathématique et la notion de «fonction» utilisée dans la programmation impérative est que les fonctions impératives peuvent avoir des effets secondaires, modifiant la valeur de l'état du programme. De ce fait, ils manquent de transparence référentielle, c'est-à-dire qu'une même expression de langage peut donner des valeurs différentes à des moments différents en fonction de l'état du programme en cours d'exécution. Inversement, dans le code fonctionnel, la valeur de sortie d'une fonction ne dépend que des arguments qui sont entrés dans la fonction, donc appeler une fonction
f
deux fois avec la même valeur pour un argumentx
produira le même résultatf(x)
les deux fois. L'élimination des effets secondaires peut faciliter la compréhension et la prédiction du comportement d'un programme, ce qui est l'une des principales motivations du développement de la programmation fonctionnelle.
Au paragraphe 2 où il est dit
Inversement, dans le code fonctionnel, la valeur de sortie d'une fonction dépend uniquement des arguments qui sont entrés dans la fonction, donc appeler une fonction
f
deux fois avec la même valeur pour un argumentx
produira le même résultat lesf(x)
deux fois.
N'est-ce pas exactement le même cas pour la programmation procédurale?
Que faut-il rechercher dans la procédure par rapport au fonctionnel qui se démarque?
Réponses:
Programmation fonctionnelle
La programmation fonctionnelle fait référence à la capacité de traiter les fonctions comme des valeurs.
Considérons une analogie avec des valeurs «régulières». Nous pouvons prendre deux valeurs entières et les combiner à l'aide de l'
+
opérateur pour obtenir un nouvel entier. Ou nous pouvons multiplier un entier par un nombre à virgule flottante pour obtenir un nombre à virgule flottante.En programmation fonctionnelle, nous pouvons combiner deux valeurs de fonction pour produire une nouvelle valeur de fonction à l'aide d'opérateurs tels que composer ou lever . Ou nous pouvons combiner une valeur de fonction et une valeur de données pour produire une nouvelle valeur de données à l'aide d'opérateurs tels que map ou fold .
Notez que de nombreux langages ont des capacités de programmation fonctionnelles - même des langages qui ne sont généralement pas considérés comme des langages fonctionnels. Même le grand-père FORTRAN prenait en charge les valeurs de fonction, bien qu'il n'offrait pas grand-chose en termes d'opérateurs de combinaison de fonctions. Pour qu'un langage soit qualifié de «fonctionnel», il doit englober en grande partie les capacités de programmation fonctionnelle.
Programmation procédurale
La programmation procédurale fait référence à la capacité d'encapsuler une séquence commune d'instructions dans une procédure afin que ces instructions puissent être invoquées de nombreux endroits sans recourir au copier-coller. Les procédures étant un développement très précoce de la programmation, la capacité est presque invariablement liée au style de programmation exigé par la programmation en langage machine ou assembleur: un style qui met l'accent sur la notion d'emplacements de stockage et d'instructions qui déplacent les données entre ces emplacements.
Contraste
Les deux styles ne sont pas vraiment opposés - ils sont simplement différents l'un de l'autre. Il existe des langages qui englobent pleinement les deux styles (LISP, par exemple). Le scénario suivant peut donner une idée de certaines différences dans les deux styles. Écrivons du code pour une exigence absurde où nous voulons déterminer si tous les mots d'une liste ont un nombre impair de caractères. Tout d'abord, le style procédural:
Je vais prendre pour acquis que cet exemple est compréhensible. Maintenant, style fonctionnel:
Travaillant de l'intérieur vers l'extérieur, cette définition fait les choses suivantes:
compose(odd, length)
combine les fonctionsodd
etlength
pour produire une nouvelle fonction qui détermine si la longueur d'une chaîne est impaire.map(..., words)
appelle cette nouvelle fonction pour chaque élément danswords
, retournant finalement une nouvelle liste de valeurs booléennes, chacune indiquant si le mot correspondant a un nombre impair de caractères.apply(and, ...)
applique l'opérateur "et" à la liste résultante, et -ing tous les booléens ensemble pour donner le résultat final.Vous pouvez voir à partir de ces exemples que la programmation procédurale est très préoccupée par le déplacement des valeurs dans les variables et la description explicite des opérations nécessaires pour produire le résultat final. En revanche, le style fonctionnel met l'accent sur la combinaison de fonctions nécessaires pour transformer l'entrée initiale en sortie finale.
L'exemple montre également les tailles relatives typiques du code procédural par rapport au code fonctionnel. En outre, cela démontre que les caractéristiques de performance du code procédural peuvent être plus faciles à voir que celles du code fonctionnel. Considérez: les fonctions calculent-elles la longueur de tous les mots de la liste, ou est-ce que chacun s'arrête immédiatement après avoir trouvé le premier mot de longueur paire? D'un autre côté, le code fonctionnel permet une implémentation de haute qualité pour effectuer une optimisation assez sérieuse car il exprime principalement une intention plutôt qu'un algorithme explicite.
Lectures complémentaires
Cette question revient souvent ... voir, par exemple:
La conférence du prix Turing de John Backus explique en détail les motivations de la programmation fonctionnelle:
La programmation peut-elle être libérée du style von Neumann?
Je ne devrais vraiment pas mentionner ce document dans le contexte actuel, car il devient assez technique, assez rapidement. Je n'ai tout simplement pas pu résister parce que je pense que c'est vraiment fondamental.
Addendum - 2013
Les commentateurs soulignent que les langages contemporains populaires offrent d'autres styles de programmation au-delà de la procédure et du fonctionnel. Ces langages offrent souvent un ou plusieurs des styles de programmation suivants:
Consultez les commentaires ci-dessous pour obtenir des exemples de la manière dont les exemples de pseudo-code de cette réponse peuvent bénéficier de certaines des fonctionnalités disponibles dans ces autres styles. En particulier, l'exemple procédural bénéficiera de l'application de pratiquement n'importe quel concept de niveau supérieur.
Les exemples exposés évitent délibérément de se mélanger à ces autres styles de programmation afin de souligner la distinction entre les deux styles en discussion.
la source
odd_words(words)
définition fait quelque chose de différent de la réponseallOdd
. Pour le filtrage et le mappage, les compréhensions de liste sont souvent préférées, mais ici la fonctionallOdd
est censée réduire une liste de mots à une seule valeur booléenne.La vraie différence entre la programmation fonctionnelle et impérative est l'état d'esprit - les programmeurs impératifs pensent aux variables et aux blocs de mémoire, tandis que les programmeurs fonctionnels se demandent: «Comment puis-je transformer mes données d'entrée en données de sortie» - votre «programme» est le pipeline et un ensemble de transformations sur les données pour les faire passer de l'entrée à la sortie. C'est la partie intéressante de l'OMI, pas le bit "Tu n'utiliseras pas de variables".
En conséquence de cet état d'esprit, les programmes de PF décrivent généralement ce qui va se passer, au lieu du mécanisme spécifique de la façon dont cela se produira - c'est puissant parce que si nous pouvons clairement indiquer ce que signifie «Sélectionner», «Où» et «Agréger», nous sont libres d'échanger leurs implémentations, tout comme nous le faisons avec AsParallel () et soudainement, notre application monothread évolue vers n cœurs.
la source
Non, car le code procédural peut avoir des effets secondaires. Par exemple, il peut stocker l'état entre les appels.
Cela dit, il est possible d'écrire du code qui satisfait cette contrainte dans des langages considérés comme procéduraux. Et il est également possible d'écrire du code qui brise cette contrainte dans certains langages considérés comme fonctionnels.
la source
Je ne suis pas d'accord avec la réponse de WReach. Déconstruisons un peu sa réponse pour voir d'où vient le désaccord.
Tout d'abord, son code:
et
La première chose à noter est qu'il confond:
programmation, et manque la possibilité pour la programmation de style itératif d'avoir un flux de contrôle plus explicite qu'un style fonctionnel typique.
Parlons rapidement de ceux-ci.
Le style centré sur l'expression est celui où les choses, autant que possible, s'évaluent aux choses. Bien que les langages fonctionnels soient réputés pour leur amour des expressions, il est en fait possible d'avoir un langage fonctionnel sans expressions composables. Je vais en inventer une, où il n'y a pas d' expressions, simplement des déclarations.
C'est à peu près la même chose que celle donnée précédemment, sauf que les fonctions sont enchaînées uniquement via des chaînes d'instructions et de liaisons.
Un style de programmation centré sur l'itérateur pourrait être celui de Python. Utilisons un style purement itératif, centré sur l'itérateur:
Ce n'est pas fonctionnel, car chaque clause est un processus itératif, et ils sont liés ensemble par une pause et une reprise explicites des cadres de pile. La syntaxe peut s'inspirer en partie d'un langage fonctionnel, mais elle est appliquée à une incarnation complètement itérative de celui-ci.
Bien sûr, vous pouvez compresser ceci:
L'impératif n'a pas l'air si mal maintenant, hein? :)
Le dernier point concernait un flux de contrôle plus explicite. Réécrivons le code original pour utiliser ceci:
En utilisant des itérateurs, vous pouvez avoir:
Alors, quel est l'intérêt d'un langage fonctionnel si la différence est entre:
La principale caractéristique définitive d'un langage de programmation fonctionnel est qu'il supprime la mutation dans le cadre du modèle de programmation typique. Les gens pensent souvent que cela signifie qu'un langage de programmation fonctionnel n'a pas d'instructions ou utilise des expressions, mais ce sont des simplifications. Un langage fonctionnel remplace le calcul explicite par une déclaration de comportement, sur laquelle le langage effectue ensuite une réduction.
Se limiter à ce sous-ensemble de fonctionnalités vous permet d'avoir plus de garanties sur les comportements de vos programmes, et cela vous permet de les composer plus librement.
Lorsque vous avez un langage fonctionnel, créer de nouvelles fonctions est généralement aussi simple que de composer des fonctions étroitement liées.
Ce n'est pas simple, voire impossible, si vous n'avez pas explicitement contrôlé les dépendances globales d'une fonction. La meilleure caractéristique de la programmation fonctionnelle est que vous pouvez constamment créer des abstractions plus génériques et être sûr qu'elles peuvent être combinées en un tout plus grand.
la source
apply
n'est pas tout à fait la même chose qu'unfold
orreduce
, même si je suis d'accord avec la belle capacité d'avoir des algorithmes très génériques.apply
signifierfold
oureduce
, mais il me semble que cela doit être dans ce contexte pour qu'il renvoie un booléen.Dans le paradigme procédural (devrais-je plutôt dire «programmation structurée»?), Vous avez partagé une mémoire mutable et des instructions qui la lisent / l'écrivent dans une séquence (l'une après l'autre).
Dans le paradigme fonctionnel, vous avez des variables et des fonctions (au sens mathématique: les variables ne varient pas dans le temps, les fonctions ne peuvent calculer quelque chose qu'en fonction de leurs entrées).
(Ceci est simplifié à l'extrême, par exemple, les FPL ont généralement des fonctionnalités pour travailler avec une mémoire mutable alors que les langages procéduraux peuvent souvent prendre en charge des procédures d'ordre supérieur, donc les choses ne sont pas aussi claires; mais cela devrait vous donner une idée)
la source
The Charming Python: La programmation fonctionnelle en Python d' IBM Developerworks m'a vraiment aidé à comprendre la différence.
Surtout pour quelqu'un qui connaît un peu Python, les exemples de code de cet article dans lesquels faire différentes choses fonctionnellement et procéduralement sont contrastées, peuvent clarifier la différence entre la programmation procédurale et fonctionnelle.
la source
En programmation fonctionnelle, pour raisonner sur la signification d'un symbole (nom de variable ou de fonction), il suffit de connaître 2 choses: la portée actuelle et le nom du symbole. Si vous avez un langage purement fonctionnel avec immuabilité, ce sont tous deux des concepts "statiques" (désolé pour le nom très surchargé), ce qui signifie que vous pouvez voir les deux - la portée actuelle et le nom - simplement en regardant le code source.
En programmation procédurale, si vous voulez répondre à la question quelle est la valeur derrière
x
vous devez également savoir comment vous y êtes arrivé, la portée et le nom seuls ne suffisent pas. Et c'est ce que je considérerais comme le plus grand défi car ce chemin d'exécution est une propriété "runtime" et peut dépendre de tellement de choses différentes, que la plupart des gens apprennent à simplement le déboguer et non à essayer de récupérer le chemin d'exécution.la source
J'ai récemment réfléchi à la différence en termes de problème d'expression . La description de Phil Wadler est souvent citée, mais la réponse acceptée à cette question est probablement plus facile à suivre. Fondamentalement, il semble que les langages impératifs ont tendance à choisir une approche du problème, tandis que les langages fonctionnels ont tendance à choisir l'autre.
la source
Une différence claire entre les deux paradigmes de programmation est l'état.
Dans la programmation fonctionnelle, l'état est évité. En termes simples, aucune variable ne sera affectée d'une valeur.
Exemple:
Cependant, la programmation procédurale utilise l'état.
Exemple:
la source