Quelle est la différence entre la programmation procédurale et la programmation fonctionnelle?

j'ai lu les articles de Wikipédia pour programmation procédurale et programmation fonctionnelle , mais je suis encore un peu confus. Quelqu'un pourrait-il la faire bouillir jusqu'à l'âme?

198
demandé sur Steve M 2008-08-22 23:29:45

14 réponses

un langage fonctionnel (idéalement) vous permet d'écrire une fonction mathématique, c.-à-d. une fonction qui prend n arguments et renvoie une valeur. Si le programme est exécuté, cette fonction est logiquement évaluée comme nécessaire. 1

un langage procédural, d'autre part, exécute une série de séquentielle pas. (Il y a une façon de transformer la logique séquentielle en logique fonctionnelle appelée continuation passing style .)

par conséquent, 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 de l'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 un généralisation. La propriété d'évaluer un calcul quand son résultat est nécessaire plutôt que séquentiellement où il est appelé est connu comme "paresse", et pas tous les langages fonctionnels sont en fait universellement paresseux, ni est paresse limitée à la programmation fonctionnelle. La description fournie ici fournit plutôt un "cadre mental" pour réfléchir à différents styles de programmation qui ne sont pas des catégories distinctes et opposées, mais plutôt des idées fluides.

117
répondu Konrad Rudolph 2016-07-07 13:59:22

essentiellement les deux styles, sont comme le Yin et le Yang. On est organisé, tandis que les autres 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 avec une nouvelle version, qui embrasse les deux styles de programmation. ( Perl 6 et D 2 )

procédural:

  • La sortie de routine n'a pas toujours une corrélation directe avec l'entrée.
  • Tout est fait dans un ordre spécifique.
  • l'Exécution d'une routine peut avoir des effets secondaires.
  • tend à mettre l'accent sur la mise en œuvre de solutions de manière linéaire.

Perl 6

sub factorial ( UInt:D $n is copy ) returns UInt {

  # modify "outside" state
  state $call-count++;
  # in this case it is rather pointless as
  # it can't even be accessed from outside

  my $result = 1;

  loop ( ; $n > 0 ; $n-- ){

    $result *= $n;

  }

  return $result;
}

D 2

int factorial( int n ){

  int result = 1;

  for( ; n > 0 ; n-- ){
    result *= n;
  }

  return result;
}

fonctionnel:

  • souvent récursif.
  • renvoie Toujours la même sortie pour une entrée donnée.
  • L'ordre d'évaluation n'est généralement pas défini.
  • doit être apatride. c'est à dire Aucune opération ne peut avoir d'effets secondaires.
  • bon ajustement pour l'exécution parallèle
  • tend à mettre l'accent sur une approche de diviser pour mieux régner.
  • peut avoir la caractéristique D'une évaluation paresseuse.

Haskell

(copié de Wikipedia );

fac :: Integer -> Integer

fac 0 = 1
fac n | n > 0 = n * fac (n-1)

ou sur une ligne:

fac n = if n > 0 then n * fac (n-1) else 1

Perl 6

proto sub factorial ( UInt:D $n ) returns UInt {*}

multi sub factorial (  0 ) { 1 }
multi sub factorial ( $n ) { $n * samewith $n-1 } # { $n * factorial $n-1 }

D 2

pure int factorial( invariant int n ){
  if( n <= 1 ){
    return 1;
  }else{
    return n * factorial( n-1 );
  }
}

note de Côté:

factoriel est en fait un exemple courant pour montrer combien il est facile de créer de nouveaux opérateurs dans Perl 6 de la même manière que vous créeriez un sous-programme. Cette fonctionnalité est tellement ancré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 multi candidats aux opérateurs existants.

sub postfix:< ! > ( UInt:D $n --> UInt )
  is tighter(&infix:<*>)
  { [*] 2 .. $n }

say 5!; # 120␤

cet exemple montre également la création d'une plage ( 2..$n ) et le méta-opérateur de réduction de liste ( [ OPERATOR ] LIST ) combiné avec l'opérateur de multiplication numérique d'infix. ( * )

Il montre également que vous pouvez mettre --> UInt dans la signature au lieu de returns UInt après elle.

( vous pouvez vous en tirer en démarrant la gamme avec 2 comme la multiplication "opérateur" retournera 1 lorsqu'il est appelé sans aucun argument )

80
répondu Brad Gilbert 2017-02-08 14:07:39

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:

fonctionnel programmation axée sur expressions

procédural programmation axée sur déclarations

Les Expressions

ont des valeurs. Un programme fonctionnel est une expression dont la valeur est une séquence de instructions pour l'ordinateur, de réaliser.

Les énoncés

n'ont pas de valeurs et modifient plutôt 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 pas de moyen de manipuler l'état (ils pourraient encore avoir une construction syntaxique appelé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 les 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 parce que tout dans un programme est une déclaration qui manipule l'état des registres et de la mémoire de la machine.

ce qui prête à confusion, c'est que la grande majorité des émissions les langues contiennent à la fois des expressions et des énoncés, vous permettant de mélanger des paradigmes. Les langues peuvent être classées comme plus fonctionnelles ou plus procédurales en fonction de la mesure dans laquelle elles encouragent l'utilisation d'énoncés par rapport à des expressions.

par exemple, C serait plus fonctionnel que COBOL parce qu'un appel de fonction est une expression, alors qu'appeler 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 l'évaluation de court-circuit (test && path1 || path2 par opposition aux instructions if). Scheme serait plus fonctionnel que Python parce que tout dans scheme est une expression.

vous pouvez encore écrire dans un style fonctionnel dans un langage qui encourage le paradigme procédural et vice versa. C'est juste plus difficile et/ou plus difficile à écrire dans un paradigme qui n'est pas encouragé par la langue.

48
répondu Omnimike 2012-11-28 08:32:07

en informatique, la programmation fonctionnelle est un paradigme de programmation qui traite le calcul comme l'évaluation de fonctions mathématiques et évite l'état et les données mutables. Il met l'accent sur l'application des fonctions, en contraste avec le style de programmation procédurale qui met l'accent sur les changements d'état.

40
répondu juan 2008-08-22 19:34:42

je crois que la procédure/fonctionnel/de l'objectif de la programmation, à propos de la façon d'aborder un problème.

le premier style prévoit tout en étapes, et résout le problème en mettant en œuvre une étape (une procédure) à la fois. D'autre part, la programmation fonctionnelle mettrait l'accent sur l'approche de 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 pour 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, dont chacun possède des caractéristiques (quelque peu) uniques, et interagirait avec d'autres. À partir de ces interactions, le résultat allait émerger.

Chaque style de programmation a ses propres avantages et inconvénients. Par conséquent, faire quelque chose comme la "programmation pure" (c'est - à-dire purement procédurale- personne ne le fait, en la voie, qui est un peu bizarre - ou purement fonctionnelle ou purement objective) est très difficile, voire impossible, à l'exception de quelques problèmes élémentaires spécialement conçus pour démontrer l'avantage d'un style de programmation (d'où, nous appelons ceux qui aiment la pureté "weenie" :D).

puis, à partir de ces styles, nous avons des langages de programmation qui est conçu pour être optimisé pour certains de chaque style. Par exemple, Assembler est une question de procédure. OK, la plupart des premières langues sont procédurales, 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 "axée sur l'argent," mais qui est sujet pour une autre discussion). Aussi objectif est Smalltalk. À l'école fonctionnelle, nous aurions "presque fonctionnel" (certains les considéraient comme impurs) la famille Lisp et la famille ML et beaucoup de "purement fonctionnel" Haskell, Erlang, etc. Au fait, il existe de nombreux langages généraux tels que Perl, Python, Ruby.

25
répondu Aaron Hall 2015-04-10 03:07:14

pour développer le commentaire de Konrad:

par conséquent, un programme purement fonctionnel donne toujours la même valeur pour un intrant, et l'ordre d'évaluation n'est pas bien défini;

pour cette Raison, le code fonctionnel est généralement plus facile à paralléliser. Comme il n'y a (généralement) aucun effet secondaire des fonctions, et qu'ils (généralement) agissent simplement sur leurs arguments, beaucoup de questions de concurrence disparaissent.

la programmation fonctionnelle est également utilisée lorsque vous avez besoin d'être capable de proving votre code est correct. C'est beaucoup plus difficile à faire avec programmation procédurale (pas facile avec fonctionnel, mais encore plus facile).

avertissement: je n'ai pas utilisé la programmation fonctionnelle depuis des années, et seulement récemment commencé à regarder à nouveau, donc je ne pourrais pas être complètement correct ici. :)

12
répondu Herms 2008-08-22 19:53:55

une chose que je n'avais pas vraiment vu souligné ici est que les langages fonctionnels modernes tels que Haskell vraiment plus sur les fonctions de première classe pour le contrôle de flux que la récursion explicite. Vous n'avez pas besoin de définir factoriellement dans Haskell, comme cela a été fait ci-dessus. Je pense que quelque chose comme

fac n = foldr (*) 1 [1..n]

est une construction parfaitement idiomatique, et beaucoup plus proche en esprit de l'utilisation d'une boucle que de l'utilisation de la récursion explicite.

11
répondu C Hogg 2008-08-24 12:28:00

les langages procéduraux ont tendance à garder la trace de l'état (en utilisant des variables) et ont tendance à s'exécuter comme une séquence d'étapes. Les langages purement fonctionnels ne tiennent pas compte de l'état, utilisent des valeurs immuables et ont tendance à s'exécuter comme une série de dépendances. Dans de nombreux cas, l'état de la pile d'appel contiendra les informations qui serait équivalente à celle qui serait stocké dans les variables d'état dans le code de procédure.

la récursion est un exemple classique de style fonctionnel programmation.

6
répondu Wedge 2008-08-22 21:11:48

Konrad a dit:

en conséquence, un programme purement fonctionnel donne toujours la même valeur pour un input, et l'ordre d'évaluation n'est pas bien définie; ce qui signifie que les valeurs incertaines comme les entrées des utilisateurs ou les valeurs aléatoires sont difficiles à modéliser dans des langages purement fonctionnels.

l'ordre d'évaluation dans un programme purement fonctionnel peut être difficile à raisonner (surtout avec paresse) ou même sans importance, mais je pense que le fait de dire qu'elle n'est pas bien définie donne l'impression qu'on ne peut pas dire si votre programme va fonctionner du tout!

peut-être une meilleure explication serait que le flux de contrôle dans les programmes fonctionnels est basé sur quand la valeur des arguments d'une fonction sont nécessaires. La bonne chose à ce sujet que dans les programmes bien écrits, l'état devient explicite: chaque fonction Liste ses entrées comme paramètres au lieu de arbitrairement munging l'état global. Donc, à un certain niveau, il est plus facile de raisonner sur l'ordre d'évaluation en ce qui concerne une fonction à la fois . Chaque fonction peut ignorer le reste de l'univers et de se concentrer sur ce qu'il doit faire. Lorsqu'elles sont combinées, les fonctions sont garanties de fonctionner de la même manière[1] qu'elles le seraient isolément.

... il est difficile de modéliser des valeurs incertaines comme les entrées des utilisateurs ou des valeurs aléatoires les langues fonctionnelles.

la solution au problème d'entrée dans les programmes purement fonctionnels est d'intégrer un langage impératif comme un DSL en utilisant une abstraction suffisamment puissante . Dans les langues impératives (ou non-pures fonctionnelles) ce n'est pas nécessaire parce que vous pouvez "tricher" et passer l'état implicitement et l'ordre d'évaluation est explicite (que vous le vouliez ou non). En raison de cette "tricherie" et de l'évaluation forcée de tous les paramètres à chaque fonction, langues impératives 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 de fil et/ou parallélisable par défaut , 3) et la mise en œuvre de quelque chose comme undo (voyage dans le temps) nécessite un travail minutieux (programmeur impératif doit stocker une recette pour obtenir l'ancienne valeur(s) de retour!), alors que la programmation purement fonctionnelle vous achète toutes ces choses-et quelques autres que j'ai peut-être oubliées - "gratuitement".

I j'espère que ça ne ressemble pas à du fanatisme, je voulais juste ajouter un peu de perspective. La programmation impérative et surtout la programmation de paradigme mixte dans des langages puissants comme C # 3.0 sont toujours des moyens totalement efficaces pour obtenir des choses faites et il n'y a pas de point d'argent .

[1]... sauf peut-être concernant l'utilisation de la mémoire (cf. foldl et foldl' en Haskell).

6
répondu Jared Updike 2009-11-06 21:56:33

pour développer le commentaire de Konrad:

et l'ordre d'évaluation n'est pas bien défini

certaines langues fonctionnelles ont ce qu'on appelle L'évaluation paresseuse. Ce qui signifie qu'une fonction n'est pas exécutée jusqu'à ce que la valeur est nécessaire. Jusqu'à ce moment, la fonction elle-même est ce qui se transmet.

les langues procédurales sont l'étape 1 l'étape 2 l'étape 3... si à l'étape 2 vous dites ajouter 2 + 2, il le fait bien puis. Dans l'évaluation différée vous dirais ajouter 2 + 2, mais si le résultat n'est jamais utilisé, il ne fait jamais le plus.

5
répondu Brian Leahy 2009-02-16 14:10:18

programmation fonctionnelle est identique à la procédure de programmation dans lequel les variables globales sont des pas qui est utilisé.

5
répondu Nir O. 2017-03-04 06:22:55

si vous avez une chance, je vous recommande D'obtenir un exemplaire du Lisp/Scheme, et d'y faire quelques projets. La plupart des idées qui sont récemment devenues des bandwagons ont été exprimées dans le Lisp il y a des décennies: programmation fonctionnelle, continuations (sous forme de fermetures), collecte de déchets, même XML.

donc ce serait un bon moyen d'avoir une longueur d'avance sur toutes ces idées actuelles, et un peu plus d'ailleurs, comme le calcul symbolique.

Vous devez savoir ce que la programmation fonctionnelle est bon, et ce qui n'est pas bon pour. Il 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.

4
répondu Mike Dunlavey 2008-12-23 15:10:51

@Creighton:

dans Haskell il y a une fonction de bibliothèque appelée produit :

prouduct list = foldr 1 (*) list

ou tout simplement:

product = foldr 1 (*)

donc le" idiomatique "factoriel

fac n = foldr 1 (*)  [1..n]

serait simplement

fac n = product [1..n]
3
répondu Jared Updike 2008-08-26 15:20:21

programmation Procédurale divise les séquences d'états et à la condition que les constructions en blocs distincts appelés les procédures qui sont paramétrées sur des arguments (non-fonctionnelle) des valeurs.

la programmation fonctionnelle est la même sauf que les fonctions sont des valeurs de première classe, de sorte qu'elles peuvent être passées en argument à d'autres fonctions et retournées en Résultat d'appels de fonction.

noter que la programmation fonctionnelle est une généralisation de programmation procédurale dans cette interprétation. Toutefois, une minorité interprète "programmation fonctionnelle" comme signifiant sans effet secondaire, ce qui est très différent mais non pertinent pour tous les principaux langages fonctionnels à l'exception de Haskell.

2
répondu Jon Harrop 2015-04-10 03:11:13