J'ai lu les articles Wikipedia pour la programmation procédurale et la programmation fonctionnelle , mais je suis toujours légèrement confus. Quelqu'un pourrait-il le réduire au cœur?
247
J'ai lu les articles Wikipedia pour la programmation procédurale et la programmation fonctionnelle , mais je suis toujours légèrement confus. Quelqu'un pourrait-il le réduire au cœur?
Réponses:
Un langage fonctionnel (idéalement) vous permet d'écrire une fonction mathématique, c'est-à-dire une fonction qui prend n arguments et renvoie une valeur. Si le programme est exécuté, cette fonction est évaluée logiquement au besoin. 1
Un langage procédural, d'autre part, effectue une série d' étapes séquentielles . (Il existe un moyen de transformer la logique séquentielle en logique fonctionnelle appelée style de passage de continuation .)
En conséquence, un programme purement fonctionnel donne toujours la même valeur pour une entrée et l'ordre d'évaluation n'est pas bien défini; ce qui signifie que les valeurs incertaines comme les entrées utilisateur ou les valeurs aléatoires sont difficiles à modéliser dans des langages purement fonctionnels.
1 Comme tout le reste dans cette réponse, c'est une généralisation. Cette propriété, qui évalue un calcul lorsque son résultat est nécessaire plutôt que séquentiellement là où il est appelé, est appelée «paresse». Tous les langages fonctionnels ne sont pas universellement paresseux, ni la paresse limitée à la programmation fonctionnelle. La description donnée ici fournit plutôt un «cadre mental» pour penser à différents styles de programmation qui ne sont pas des catégories distinctes et opposées mais plutôt des idées fluides.
la source
Fondamentalement, les deux styles sont comme le Yin et le Yang. L'un est organisé, l'autre chaotique. Il y a des situations où la programmation fonctionnelle est le choix évident, et d'autres situations où la programmation procédurale est le meilleur choix. C'est pourquoi il y a au moins deux langues qui ont récemment sorti une nouvelle version, qui embrasse les deux styles de programmation. ( Perl 6 et D 2 )
De procédure:
Perl 6
D 2
Fonctionnel:
Haskell
(copié de Wikipedia );
ou en une seule ligne:
Perl 6
D 2
Note latérale:
Factorial est en fait un exemple courant pour montrer à quel point il est facile de créer de nouveaux opérateurs en Perl 6 de la même manière que vous créeriez un sous-programme. Cette fonctionnalité est tellement enracinée dans Perl 6 que la plupart des opérateurs de l'implémentation Rakudo sont définis de cette façon. Il vous permet également d'ajouter vos propres candidats multiples aux opérateurs existants.
Cet exemple montre également la création de plage (
2..$n
) et le méta-opérateur de réduction de liste ([ OPERATOR ] LIST
) combinés avec l'opérateur de multiplication d'infixe numérique. (*
)Cela montre également que vous pouvez mettre
--> UInt
la signature au lieu de l'returns UInt
ajouter.(Vous pouvez vous en sortir en commençant la plage avec
2
car "multiplier" retournera1
lorsqu'il sera appelé sans aucun argument)la source
sub postfix:<!> ($n) { [*] 1..$n }
No operation can have side effects
vous le développer?sub foo( $a, $b ){ ($a,$b).pick }
← ne renvoie pas toujours la même sortie pour la même entrée, contrairement à ce qui suitsub foo( $a, $b ){ $a + $b }
Je n'ai jamais vu cette définition donnée ailleurs, mais je pense que cela résume assez bien les différences données ici:
La programmation fonctionnelle se concentre sur les expressions
La programmation procédurale se concentre sur les déclarations
Les expressions ont des valeurs. Un programme fonctionnel est une expression dont la valeur est une séquence d'instructions à exécuter par l'ordinateur.
Les instructions n'ont pas de valeurs et modifient à la place l'état d'une machine conceptuelle.
Dans un langage purement fonctionnel, il n'y aurait pas de déclarations, dans le sens où il n'y a aucun moyen de manipuler l'état (elles pourraient toujours avoir une construction syntaxique nommée "déclaration", mais à moins qu'elle ne manipule l'état, je ne l'appellerais pas une déclaration dans ce sens ). Dans un langage purement procédural, il n'y aurait pas d'expressions, tout serait une instruction qui manipule l'état de la machine.
Haskell serait un exemple de langage purement fonctionnel car il n'y a aucun moyen de manipuler l'état. Le code machine serait un exemple de langage purement procédural car tout dans un programme est une instruction qui manipule l'état des registres et de la mémoire de la machine.
La partie déroutante est que la grande majorité des langages de programmation contiennent à la fois expressions et des instructions, vous permettant de mélanger les paradigmes. Les langages peuvent être classés comme plus fonctionnels ou plus procéduraux en fonction de la mesure dans laquelle ils encouragent l'utilisation des déclarations par rapport aux expressions.
Par exemple, C serait plus fonctionnel que COBOL car un appel de fonction est une expression, alors que l'appel d'un sous-programme dans COBOL est une instruction (qui manipule l'état des variables partagées et ne renvoie pas de valeur). Python serait plus fonctionnel que C car il vous permet d'exprimer la logique conditionnelle comme une expression en utilisant une évaluation de court-circuit (test && path1 || path2 par opposition aux instructions if). Le schéma serait plus fonctionnel que Python car tout dans le schéma est une expression.
Vous pouvez toujours écrire dans un style fonctionnel dans une langue qui encourage le paradigme procédural et vice versa. Il est juste plus difficile et / ou plus gênant d'écrire dans un paradigme qui n'est pas encouragé par la langue.
la source
En informatique, la programmation fonctionnelle est un paradigme de programmation qui traite le calcul comme l'évaluation des 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 procédurale qui met l'accent sur les changements d'état.
la source
GetUserContext()
la fonction, le contexte utilisateur serait passé. Est-ce une programmation fonctionnelle? Merci d'avance.Je crois que la programmation procédurale / fonctionnelle / objective concerne la façon d'aborder un problème.
Le premier style planifierait tout en étapes et résoudrait le problème en implémentant une étape (une procédure) à la fois. D'un autre côté, la programmation fonctionnelle mettrait l'accent sur l'approche diviser pour mieux régner, où le problème est divisé en sous-problèmes, puis chaque sous-problème est résolu (création d'une fonction pour résoudre ce sous-problème) et les résultats sont combinés pour créer la réponse à l'ensemble du problème. Enfin, la programmation objective imiterait le monde réel en créant un mini-monde à l'intérieur de l'ordinateur avec de nombreux objets, chacun ayant des caractéristiques (quelque peu) uniques, et interagissant avec les autres. De ces interactions, le résultat émergerait.
Chaque style de programmation a ses propres avantages et faiblesses. Par conséquent, faire quelque chose comme de la "programmation pure" (c'est-à-dire purement procédurale - personne ne le fait d'ailleurs, ce qui est un peu bizarre - ou purement fonctionnel ou purement objectif) est très difficile, voire impossible, à l'exception de quelques problèmes élémentaires spécialement conçu pour démontrer l'avantage d'un style de programmation (par conséquent, nous appelons ceux qui aiment la pureté "weenie": D).
Ensuite, à partir de ces styles, nous avons des langages de programmation conçus pour être optimisés pour certains de chaque style. Par exemple, l'assemblage est une question de procédure. D'accord, la plupart des premiers langages sont procéduraux, pas seulement Asm, comme C, Pascal, (et Fortran, j'ai entendu). Ensuite, nous avons tous Java célèbre dans l'école objective (En fait, Java et C # est également dans une classe appelée "orientée vers l'argent", mais qui fait l'objet d'une autre discussion). L'objectif est également Smalltalk. Dans une école fonctionnelle, nous aurions «presque fonctionnel» (certains les considéraient comme impurs) la famille Lisp et la famille ML et de nombreux Haskell, Erlang «purement fonctionnels», etc. Soit dit en passant, il existe de nombreux langages généraux tels que Perl, Python , Ruby.
la source
Programmation fonctionnelle
Programmation procédurale
function_to_add_one
est une fonctionprocedure_to_add_one
est une procédureMême si vous exécutez la fonction cinq fois, chaque fois qu'elle reviendra 2
Si vous exécutez la procédure cinq fois, à la fin de la cinquième exécution, cela vous donnera 6 .
la source
Pour développer le commentaire de Konrad:
Pour cette raison, le code fonctionnel est généralement plus facile à paralléliser. Puisqu'il n'y a (généralement) aucun effet secondaire des fonctions, et qu'elles (généralement) agissent simplement sur leurs arguments, beaucoup de problèmes de concurrence disparaissent.
La programmation fonctionnelle est également utilisée lorsque vous devez être en mesure de prouver que votre code est correct. C'est beaucoup plus difficile à faire avec la programmation procédurale (pas facile avec fonctionnel, mais toujours plus facile).
Avertissement: je n'ai pas utilisé de programmation fonctionnelle depuis des années, et je n'ai recommencé à le regarder que récemment, donc je ne suis peut-être pas complètement correct ici. :)
la source
Une chose que je n'avais pas vue vraiment soulignée ici est que les langages fonctionnels modernes tels que Haskell sont vraiment plus sur les fonctions de première classe pour le contrôle de flux que la récursivité explicite. Vous n'avez pas besoin de définir récursivement factorielle dans Haskell, comme cela a été fait ci-dessus. Je pense que quelque chose comme
est une construction parfaitement idiomatique, et beaucoup plus proche dans l'esprit d'utiliser une boucle que d'utiliser une récursivité explicite.
la source
Une programmation fonctionnelle est identique à une programmation procédurale dans laquelle les variables globales ne sont pas utilisées.
la source
Les langages procéduraux ont tendance à garder une trace de l'état (à l'aide de variables) et ont tendance à s'exécuter comme une séquence d'étapes. Les langages purement fonctionnels ne gardent pas la trace de l'état, utilisent des valeurs immuables et ont tendance à s'exécuter comme une série de dépendances. Dans de nombreux cas, le statut de la pile d'appels contiendra les informations qui seraient équivalentes à celles qui seraient stockées dans des variables d'état dans le code de procédure.
La récursivité est un exemple classique de programmation de style fonctionnel.
la source
Konrad a déclaré:
L'ordre d'évaluation dans un programme purement fonctionnel peut être difficile (euh) à raisonner (en particulier avec la paresse) ou même sans importance, mais je pense que dire qu'il n'est pas bien défini donne l'impression que vous ne pouvez pas dire si votre programme va travailler du tout!
Une meilleure explication serait peut-être que le flux de contrôle dans les programmes fonctionnels est basé sur le moment où la valeur des arguments d'une fonction est nécessaire. La bonne chose à ce sujet dans les programmes bien écrits, l'état devient explicite: chaque fonction répertorie ses entrées en tant que paramètres au lieu de fusionner arbitrairement l'état global. Donc, à un certain niveau, il est plus facile de raisonner sur l'ordre d'évaluation par rapport à une fonction à la fois . Chaque fonction peut ignorer le reste de l'univers et se concentrer sur ce qu'elle doit faire. Lorsqu'elles sont combinées, les fonctions sont garanties de fonctionner de la même façon [1] qu'elles le feraient isolément.
La solution au problème d'entrée dans les programmes purement fonctionnels est d'incorporer un langage impératif en tant que DSL en utilisant une abstraction suffisamment puissante . Dans les langages impératifs (ou fonctionnels non purs), cela n'est pas nécessaire car vous pouvez "tricher" et passer l'état implicitement et l'ordre d'évaluation est explicite (que cela vous plaise ou non). En raison de cette "tricherie" et de l'évaluation forcée de tous les paramètres de chaque fonction, dans les langages impératifs 1) vous perdez la possibilité de créer vos propres mécanismes de flux de contrôle (sans macros), 2) le code n'est pas intrinsèquement sûr pour les threads et / ou parallélisable par défaut, 3) et la mise en œuvre de quelque chose comme annuler (voyage dans le temps) nécessite un travail minutieux (le programmeur doit impérativement stocker une recette pour récupérer les anciennes valeurs!), Tandis que la programmation fonctionnelle pure vous achète toutes ces choses - et quelques autres je peux ont oublié - "gratuitement".
J'espère que cela ne ressemble pas à du fanatisme, je voulais juste ajouter un peu de perspective. La programmation impérative et en particulier la programmation de paradigmes mixtes dans des langages puissants comme C # 3.0 sont toujours des moyens totalement efficaces pour faire avancer les choses et il n'y a pas de solution miracle .
[1] ... sauf éventuellement en ce qui concerne l'utilisation de la mémoire (cf. foldl et foldl 'dans Haskell).
la source
Pour développer le commentaire de Konrad:
Certains langages fonctionnels ont ce qu'on appelle l'évaluation paresseuse. Ce qui signifie qu'une fonction n'est pas exécutée tant que la valeur n'est pas requise. Jusqu'à ce moment, c'est la fonction elle-même qui est transmise.
Les langues procédurales sont l'étape 1 étape 2 étape 3 ... si à l'étape 2 vous dites ajouter 2 + 2, il le fait tout de suite. Dans une évaluation paresseuse, vous diriez ajouter 2 + 2, mais si le résultat n'est jamais utilisé, il ne fait jamais l'ajout.
la source
Si vous en avez l'occasion, je vous recommande d'obtenir une copie de Lisp / Scheme et de faire quelques projets dedans. La plupart des idées qui sont devenues ces derniers temps des bandwagons ont été exprimées en Lisp il y a des décennies: programmation fonctionnelle, continuations (comme fermetures), garbage collection, même XML.
Ce serait donc un bon moyen de prendre une longueur d'avance sur toutes ces idées actuelles, et quelques autres en plus, comme le calcul symbolique.
Vous devez savoir à quoi sert la programmation fonctionnelle et à quoi elle ne l'est pas. Ce n'est pas bon pour tout. Certains problèmes sont mieux exprimés en termes d'effets secondaires, où la même question donne des réponses différentes selon le moment où elle est posée.
la source
@Creighton:
Dans Haskell, il existe une fonction de bibliothèque appelée produit :
ou simplement:
donc la factorielle "idiomatique"
serait tout simplement
la source
La programmation procédurale divise les séquences d'instructions et les constructions conditionnelles en blocs séparés appelés procédures paramétrées sur des arguments qui sont des valeurs (non fonctionnelles).
La programmation fonctionnelle est la même, sauf que les fonctions sont des valeurs de première classe, elles peuvent donc être passées comme arguments à d'autres fonctions et renvoyées comme résultats d'appels de fonction.
Notez que la programmation fonctionnelle est une généralisation de la programmation procédurale dans cette interprétation. Cependant, une minorité interprète la «programmation fonctionnelle» comme signifiant sans effets secondaires, ce qui est assez différent mais sans pertinence pour tous les principaux langages fonctionnels, sauf Haskell.
la source
Pour comprendre la différence, il faut comprendre que le paradigme "le parrain" de la programmation procédurale et fonctionnelle est la programmation impérative .
Fondamentalement, la programmation procédurale n'est qu'un moyen de structurer des programmes impératifs dans lesquels la principale méthode d'abstraction est la «procédure». (ou "fonction" dans certains langages de programmation). Même la programmation orientée objet est juste une autre façon de structurer un programme impératif, où l'état est encapsulé dans des objets, devenant un objet avec un "état actuel", plus cet objet a un ensemble de fonctions, de méthodes et d'autres choses qui vous permettent de le programmeur manipule ou met à jour l'état.
Maintenant, en ce qui concerne la programmation fonctionnelle, l' essentiel dans son approche est qu'il identifie les valeurs à prendre et comment ces valeurs doivent être transférées. (il n'y a donc pas d'état et pas de données mutables car il prend les fonctions comme valeurs de première classe et les transmet comme paramètres à d'autres fonctions).
PS: comprendre chaque paradigme de programmation utilisé devrait clarifier les différences entre chacun d'eux.
PSS: En fin de compte, les paradigmes de programmation ne sont que des approches différentes pour résoudre les problèmes.
PSS: cette réponse quora a une grande explication.
la source
Aucune des réponses ici ne montre une programmation fonctionnelle idiomatique. La réponse factorielle récursive est idéale pour représenter la récursivité en FP, mais la majorité du code n'est pas récursif, donc je ne pense pas que cette réponse soit pleinement représentative.
Supposons que vous ayez un tableau de chaînes et que chaque chaîne représente un entier comme "5" ou "-200". Vous souhaitez vérifier ce tableau d'entrée de chaînes par rapport à votre scénario de test interne (à l'aide de la comparaison d'entiers). Les deux solutions sont présentées ci-dessous
De procédure
Fonctionnel
Alors que les langages fonctionnels purs sont généralement des langages de recherche (comme le monde réel aime les effets secondaires gratuits), les langages procéduraux du monde réel utiliseront la syntaxe fonctionnelle beaucoup plus simple, le cas échéant.
Ceci est généralement implémenté avec une bibliothèque externe comme Lodash , ou disponible intégré avec des langages plus récents comme Rust . La levée de la programmation fonctionnelle lourde se fait avec des fonctions / concepts tels que
map
,filter
,reduce
,currying
,partial
, les trois derniers dont vous pouvez consulter pour une meilleure compréhension.Addenda
Pour être utilisé dans la nature, le compilateur devra normalement déterminer comment convertir la version fonctionnelle en version procédurale en interne, car la surcharge d'appel de fonction est trop élevée. Les cas récursifs tels que la factorielle illustrée utiliseront des astuces comme l' appel de queue pour supprimer l'utilisation de la mémoire O (n). Le fait qu'il n'y ait pas d'effets secondaires permet aux compilateurs fonctionnels d'implémenter l'
&& ret
optimisation même lorsque la.reduce
dernière est effectuée. L'utilisation de Lodash dans JS ne permet évidemment aucune optimisation, c'est donc un coup sûr pour les performances (ce qui n'est généralement pas un problème avec le développement web). Des langages comme Rust optimiseront en interne (et auront des fonctions telles que l'try_fold
assistance à l'&& ret
optimisation).la source