web-dev-qa-db-fra.com

Programmation fonctionnelle, déclarative et impérative

Que signifient les termes programmation fonctionnelle, déclarative et impérative?

459
curiouskitty

Au moment de la rédaction de cet article, les réponses les plus votées sur cette page sont imprécises et confuses sur la définition déclarative par rapport à la définition impérative, y compris la réponse qui cite Wikipedia. Certaines réponses confondent les termes de différentes manières.

Reportez-vous également à mon explication pour expliquer pourquoi la programmation par feuille de calcul est déclarative, indépendamment du fait que les formules mutent les cellules.

De plus, plusieurs réponses affirment que la programmation fonctionnelle doit être un sous-ensemble du déclaratif. Cela dépend de la différence entre "fonction" et "procédure". Permet de gérer impératif vs déclaratif en premier.

Définition de expression déclarative

L'attribut seulement qui peut éventuellement différencier une expression déclarative d'une expression impératif est la transparence référentielle. (RT) de ses sous-expressions. Tous les autres attributs sont soit partagés entre les deux types d'expressions, soit dérivés de la RT.

Un langage déclaratif à 100% (c'est-à-dire un langage dans lequel toutes les expressions possibles sont RT) ne permet pas (parmi d'autres RT exigences) de permettre la mutation de valeurs stockées, par ex. HTML et la plupart de Haskell.

Définition de expression RT

La RT est souvent qualifiée de "sans effet secondaire". Le terme effets n'a pas de définition précise; certaines personnes ne sont donc pas d'accord pour dire que "pas d'effets secondaires" est identique à RT. RT a un définition précise .

Comme chaque sous-expression est conceptuellement un appel de fonction, RT nécessite que la mise en oeuvre d'une fonction (c'est-à-dire la ou les expressions à l'intérieur de la fonction appelée) ne puisse pas accéder à l'état mutable external à la fonction (accéder à la mutable local état est autorisé). En termes simples, la fonction (implémentation) devrait être pure.

Définition de fonction pure

On dit souvent qu'une fonction pure n'a "pas d'effets secondaires". Le terme effets n'a pas de définition précise, alors certaines personnes ne sont pas d'accord.

Les fonctions pures ont les attributs suivants.

  • la seule sortie observable est la valeur de retour.
  • la seule dépendance de sortie est les arguments.
  • les arguments sont entièrement déterminés avant toute sortie est générée.

Rappelez-vous que RT s'applique aux expressions (qui incluent les appels de fonction) et que la pureté s'applique aux (implémentations de) fonctions.

Un exemple obscur de fonctions impures qui créent des expressions RT est la concurrence, mais c'est parce que la pureté est interrompue au niveau de la couche d'abstraction des interruptions. Vous n'avez pas vraiment besoin de savoir cela. Pour faire des expressions RT, vous appelez des fonctions pures.

Attributs dérivés de RT

Tout autre attribut cité pour la programmation déclarative, par ex. le citation de 1999 utilisé par Wikipedia, provient de RT ou est partagé avec une programmation impérative. Prouvant ainsi que ma définition précise est correcte.

Remarque, l'immuabilité de valeurs externes est un sous-ensemble des exigences pour RT.

  • Les langages déclaratifs n'ont pas de structures de contrôle en boucle, par exemple. for et while, car en raison de son immuabilité , la condition de la boucle ne changerait jamais.

  • Les langages déclaratifs n'expriment pas de flux de contrôle autres que l'ordre de fonction imbriqué (ou dépendances logiques), car en raison de l'immutabilité , les autres choix d'ordre d'évaluation ne le sont pas. changer le résultat (voir ci-dessous).

  • Les langages déclaratifs expriment des "étapes" logiques (c'est-à-dire l'ordre d'appel des fonctions imbriqué RT), mais le fait que chaque appel de fonction soit une sémantique de niveau supérieur ("que faire") n'est pas une exigence de la programmation déclarative. La distinction de l'impératif est que en raison de l'immutabilité (c'est-à-dire plus généralement RT), ces "étapes" ne peuvent pas dépendre d'un état mutable, mais uniquement de l'ordre relationnel de la logique exprimée (c'est-à-dire l'ordre d'imbrication des appels de fonction, également appelés sous-expressions).

    Par exemple, le paragraphe HTML <p> ne peut pas être affiché tant que les sous-expressions (balises) du paragraphe n’ont pas été évaluées. Il n'y a pas d'état mutable, seulement une dépendance d'ordre en raison de la relation logique de la hiérarchie des balises (imbrication de sous-expressions, qui sont appels de fonctions imbriquées de manière analogue ).

  • Ainsi, il y a l'attribut dérivé d'immutabilité (plus généralement RT), que les expressions déclaratives, expriment seulement ​​les logiques relations des parties constituantes ) et pas état mutable relations.

Ordre d'évaluation

Le choix de l'ordre d'évaluation des sous-expressions ne peut donner un résultat variable que si l'un des appels de fonction n'est pas RT (c'est-à-dire que la fonction n'est pas pure), par ex. un état mutable externe à une fonction est accédé dans la fonction.

Par exemple, étant donné certaines expressions imbriquées, par exemple f( g(a, b), h(c, d) ), une évaluation rapide et paresseuse des arguments de la fonction donnera les mêmes résultats si les fonctions f, g et h sont pures.

Alors que, si les fonctions f, g et h ne sont pas pures, le choix de l'ordre d'évaluation peut donner un résultat différent.

Remarque, les expressions imbriquées sont des fonctions conceptuellement imbriquées, car les opérateurs d'expression ne sont que des appels de fonction masqués en préfixe unaire, en postfixe unaire ou en notation infixe binaire.

Tangentiellement, si tous les identifiants, par ex. a, b, c, d, sont immuable partout, l'état externe au programme n'est pas accessible (c.-à-d. Les E/S), et il n'y a pas de rupture de la couche d'abstraction, les fonctions sont toujours pures.

À propos, Haskell a une syntaxe différente, f (g a b) (h c d).

Détails de la commande d'évaluation

Une fonction est une transition d'état (pas une valeur stockée modifiable) de l'entrée à la sortie. Pour RT compositions d'appels à des fonctions pure, l'ordre d'exécution de ces transitions d'état est indépendant. La transition d'état de chaque appel de fonction est indépendante des autres, en raison de l'absence d'effets secondaires et du principe selon lequel une fonction la fonction RT peut être remplacée par sa valeur mise en cache . Pour corriger une idée fausse populaire , la composition monadique pure est toujours déclarative et RT, malgré le fait que la monade de IO de Haskell soit sans doute impure et donc impérative l'état World externe au programme (mais au sens de la mise en garde ci-dessous, les effets secondaires sont isolés).

Eager evaluation signifie que les arguments de la fonction sont évalués avant que la fonction ne soit appelée, et paresseux évaluation signifie le les arguments ne sont pas évalués jusqu'à (et si) ils sont accédés dans la fonction.

Définition : fonction paramètres sont déclarés à la fonction définition site, et fonction arguments sont fournis à la fonction call site. Connaître la différence entre paramètre et argument.

Conceptuellement, toutes les expressions sont (une composition de) appels de fonction, par exemple. les constantes sont des fonctions sans entrées, les opérateurs unaires sont des fonctions avec une entrée, les opérateurs infixes binaires sont des fonctions avec deux entrées, les constructeurs sont des fonctions et même des instructions de contrôle (par exemple, if, for, while ) peut être modélisé avec des fonctions. Les fonctions ordre que celles-ciargument ​​(ne confondez pas avec l'ordre d'appel des fonctions imbriquées) sont évaluées n'est pas déclarée par la syntaxe, par exemple. f( g() ) pourrait évaluer avec impatience le résultat de g puis f sur g ou il pourrait évaluer f et n'évaluer que par la suite g lorsque son résultat est requis dans les f.

La mise en garde, no Turing complete la langue (c’est-à-dire qui permet une récursion sans limite) est parfaitement déclarative, par ex. L'évaluation paresseuse introduit la mémoire et l'indéterminisme temporel. Mais ces effets secondaires dus au choix de l'ordre d'évaluation sont limités à la consommation de mémoire, au temps d'exécution, à la latence, à la non-terminaison et à hystérésis externe donc à la synchronisation externe.

Programmation fonctionnelle

Comme la programmation déclarative ne peut pas avoir de boucles, le seul moyen d'itérer est la récursion fonctionnelle. C'est en ce sens que la programmation fonctionnelle est liée à la programmation déclarative.

Mais la programmation fonctionnelle ne se limite pas à la programmation déclarative . La composition fonctionnelle peut être contrastée avec le sous-typage , en particulier en ce qui concerne le problème d'expression , où l'extension peut être obtenue par en ajoutant des sous-types ou une décomposition fonctionnelle . L'extension peut être un mélange des deux méthodologies.

La programmation fonctionnelle fait généralement de la fonction un objet de première classe, ce qui signifie que le type de fonction peut apparaître dans la grammaire n'importe où peut l'être n'importe quel autre type. Le résultat est que les fonctions peuvent entrer et opérer sur des fonctions, permettant ainsi de séparer les préoccupations en mettant l'accent sur la composition de la fonction, c'est-à-dire en séparant les dépendances entre les sous-calculs d'un calcul déterministe.

Par exemple, au lieu d'écrire une fonction distincte (et employant une récursion au lieu de boucles si la fonction doit également être déclarative) pour chacune d'un nombre infini d'actions spécialisées possibles pouvant être appliquées à chaque élément d'un objet. la programmation fonctionnelle utilise des fonctions d’itération réutilisables, par exemple: map, fold, filter. Ces fonctions d'itération introduisent une fonction d'action spécialisée de première classe. Ces fonctions d'itération itèrent la collection et appellent la fonction d'action spécialisée d'entrée pour chaque élément. Ces fonctions d’action sont plus concises car elles ne doivent plus contenir les instructions de bouclage pour itérer la collection.

Cependant, notez que si une fonction n'est pas pure, alors c'est vraiment une procédure. Nous pouvons peut-être soutenir que la programmation fonctionnelle qui utilise des fonctions impures est en réalité une programmation procédurale. Ainsi, si nous convenons que les expressions déclaratives sont RT, nous pouvons dire que la programmation procédurale n’est pas une programmation déclarative. Nous pourrions donc affirmer que la programmation fonctionnelle est toujours RT et doit être un sous-ensemble de la programmation déclarative.

Parallélisme

Cette composition fonctionnelle avec des fonctions de première classe peut exprimer la profondeur dans le parallélisme en séparant la fonction indépendante.

Principe de Brent: le calcul avec le travail w et la profondeur d peut être implémenté dans une PRAM à p-processeurs en temps O (max (w/p, d)).

La simultanéité et le parallélisme aussi nécessite une programmation déclarative , c'est-à-dire l'immuabilité et la RT.

Alors, d'où vient cette hypothèse dangereuse selon laquelle le parallélisme == La simultanéité vient? C’est une conséquence naturelle des langages avec des effets secondaires: lorsque votre langage a des effets secondaires partout, alors chaque fois que vous essayez de faire plus d’une chose à la fois, le non-déterminisme est essentiellement causé par l’entrelacement des effets de chaque opération. . Ainsi, dans les langages à effets secondaires, le seul moyen d’obtenir le parallélisme est la concurrence; il n’est donc pas surprenant que nous voyions souvent les deux fusionner.

Ordre d'évaluation de la PF

Notez que l'ordre d'évaluation a également un impact sur les effets secondaires de la composition fonctionnelle sur la résiliation et la performance.

Eager (CBV) et lazy (CBN) sont des duels catégoriques [ 1 ], car leur ordre d'évaluation est inversé, c'est-à-dire si les fonctions externe ou interne sont évaluées en premier. Imaginez une arborescence à l'envers, puis avide évalue les astuces de branche d'arbre de fonctions vers le haut dans la hiérarchie des branches jusqu'au tronc de fonction de niveau supérieur; tandis que, paresseux évalue du tronc jusqu'aux conseils de branche. Eager n'a pas de produits conjonctifs ("et", a/k/a catégoriques "produits") et paresseux n'a pas de coproduits disjonctifs ("ou", a/k/a catégoriques "sommes") [ 11 ].

Performance

  • Désireux

    Comme avec la non-terminaison, impatient est trop impatient avec la composition fonctionnelle conjonctive, c'est-à-dire que la structure de contrôle de composition effectue un travail inutile qui n'est pas fait avec des paresseux. Pour exemple , mappe avec empressement et sans nécessité la totalité de la liste en booléens, lorsqu'elle est composée d'un pli qui se termine par le premier élément vrai.

    Ce travail inutile est à l’origine du prétendu "jusqu’à" un extra facteur log n dans la complexité temporelle séquentielle de désireux paresseux, les deux avec des fonctions pures. Une solution consiste à utiliser des foncteurs (par exemple, des listes) avec des constructeurs paresseux (c'est-à-dire désireux avec des produits paresseux optionnels), car avec impatience, l'inconvénient de l'empressement provient de la fonction interne. En effet, les produits sont des types constructifs, c’est-à-dire des types inductifs avec une algèbre initiale sur un point de repère initial [ 11 ]

  • Paresseux

    Comme avec la non-résiliation, le paresseux est trop paresseux avec une composition fonctionnelle disjonctive, c’est-à-dire que la finalité coinductive peut survenir plus tard que nécessaire, entraînant à la fois un travail inutile et un non-déterminisme du retard qui n’est pas le cas avec désireux [ 1 ] [ 11 ]. Les exemples d'état, de minutage, de non-terminaison et d'exécution sont des exemples de finalité. Ce sont des effets secondaires impératifs, mais même dans un langage purement déclaratif (par exemple Haskell), il existe un état dans la monade IO impérative (remarque: toutes les monades ne sont pas impératives!) Implicites dans l'attribution d'espace et dans le timing. est un état relatif au monde réel impératif. L'utilisation de paresseux, même avec des coproduits optionnels enthousiastes, fuit "la paresse" dans les coproduits internes, car avec paresseux, l'inconvenance de la paresse provient de la fonction externe (voir l'exemple dans la section Non-résiliation, où == est une fonction opérateur binaire). En effet, les coproduits sont liés par la finalité, c'est-à-dire des types coinductifs avec une algèbre finale sur un objet final [ 11 ].

    Lazy cause l'indétermination dans la conception et le débogage de fonctions pour la latence et l'espace, dont le débogage dépasse probablement les capacités de la majorité des programmeurs, en raison de la dissonance entre la hiérarchie de fonctions déclarée et l'ordre d'exécution -de-évaluation. Les fonctions pures paresseuses évaluées avec impatience pourraient potentiellement introduire une non-résiliation auparavant invisible au moment de l'exécution. À l'inverse, des fonctions pures entières évaluées avec du paresseux pourraient potentiellement introduire un indéterminisme d'espace et de latence auparavant invisibles au moment de l'exécution.

Non-résiliation

Au moment de la compilation, en raison du problème de Halting et de la récursion mutuelle dans un langage complet de Turing, il n'est généralement pas garanti que les fonctions se terminent.

  • Désireux

    Avec impatience mais pas paresseux, pour la conjonction de Head "et" Tail, si Head ou Tail ne se termine pas, alors respectivement List( Head(), Tail() ).tail == Tail() ou List( Head(), Tail() ).head == Head() n'est pas vrai car le côté gauche ne se termine pas, et le côté droit ne se termine pas.

    Considérant que, avec paresseux les deux côtés se terminent. Donc, désireux est trop pressé avec les produits conjonctifs, et non terminé (y compris les exceptions d'exécution) dans les cas où cela n'est pas nécessaire.

  • Paresseux

    Paresseux mais pas pressé, pour la disjonction de 1 "ou" 2 ", si f ne se termine pas, alors List( f ? 1 : 2, 3 ).tail == (f ? List( 1, 3 ) : List( 2, 3 )).tail n'est pas vrai car le côté gauche se termine et la droite ne le fait pas.

    Considérant que, avec aucun des deux côtés ne se termine, le test d’égalité n’est jamais atteint. Ainsi, paresseux est trop paresseux avec des coproduits disjonctifs, et dans ces cas, il ne parvient pas à se terminer (y compris les exceptions d'exécution) après avoir effectué plus de travail que prévu.

[ 1 ] Continuations déclaratives et dualité catégorique, Filinski, sections 2.5.4 Comparaison des CBV et des CBN, et 3.6.1 CBV et des CBN dans le SCL.

[ 11 ] Continuations déclaratives et dualité catégorique, Filinski, sections 2.2.1 Produits et coproduits, 2.2.2 Objets terminaux et objets initiaux, 2.5.2 CBV avec produits paresseux et 2.5.3 CBN avec coproduits enthousiastes .

255
Shelby Moore III

Il n’existe pas vraiment de définition objective, non ambiguë. Voici comment I les définirait:

Impératif - L'accent est mis sur les étapes à suivre par l'ordinateur plutôt que sur ce que l'ordinateur fera (ex. C, C++ , Java).

Déclaratif - L'accent est mis sur ce que l'ordinateur devrait faire plutôt que sur la façon dont il devrait le faire (ex. SQL).

Functional - un sous-ensemble de langages déclaratifs fortement axés sur la récursivité

100
Jason Baker

impératif et déclaratif décrivent deux styles de programmation opposés. L’impératif est l’approche traditionnelle de la "recette pas à pas" tandis que le déclaratif est plus "c’est ce que je veux, maintenant vous essayez de le faire".

ces deux approches se retrouvent tout au long de la programmation, même avec le même langage et le même programme. En général, l’approche déclarative est préférable, car elle évite au programmeur d’avoir à spécifier autant de détails, tout en minimisant les risques de bugs (si vous décrivez le résultat souhaité et si un processus automatique bien testé peut fonctionner en arrière), définir les étapes, vous pouvez espérer que les choses seront plus fiables que de devoir spécifier chaque étape à la main).

d'autre part, une approche impérative vous donne plus de contrôle de bas niveau - c'est l'approche "micromanager" de la programmation. et cela peut permettre au programmeur d'exploiter la connaissance du problème pour donner une réponse plus efficace. il n’est donc pas inhabituel que certaines parties d’un programme soient écrites dans un style plus déclaratif, mais que les parties critiques pour la vitesse soient plus impératives.

comme vous pouvez l’imaginer, le langage que vous utilisez pour écrire un programme a une incidence sur votre capacité à être déclaratif - un langage doté de fonctions intelligentes permettant de déterminer ce qu’il faut faire étant donné une description du résultat autorisera une approche beaucoup plus déclarative. approche à celle où le programmeur doit d’abord ajouter ce type d’intelligence avec un code impératif avant de pouvoir construire une couche plus déclarative par dessus. Ainsi, par exemple, un langage comme prolog est considéré comme très déclaratif, car il comporte un processus intégré qui recherche des réponses.

jusqu'à présent, vous remarquerez que je n'ai pas mentionné la programmation fonctionnelle. c'est parce que c'est un terme dont la signification n'est pas immédiatement liée aux deux autres. au plus simple, la programmation fonctionnelle signifie que vous utilisez des fonctions. en particulier, vous utilisez un langage qui prend en charge les fonctions en tant que "valeurs de première classe" - cela signifie que non seulement vous pouvez écrire des fonctions, mais vous pouvez écrire des fonctions qui écrivent des fonctions (qui écrivent des fonctions qui ...), et les transmettent à les fonctions. En bref, ces fonctions sont aussi souples et courantes que des chaînes et des nombres.

il peut donc sembler étrange que fonctionnel, impératif et déclaratif soient souvent mentionnés ensemble. la raison en est une conséquence de l'idée de programmation fonctionnelle "à l'extrême". une fonction, dans son sens le plus pur, est quelque chose de mathématique - une sorte de "boîte noire" qui prend une entrée et donne toujours la même sortie. et ce genre de comportement ne nécessite pas de stocker des variables changeantes. Ainsi, si vous concevez un langage de programmation visant à implémenter une idée très pure de la programmation fonctionnelle, influencée par les mathématiques, vous finirez par rejeter en grande partie l'idée de valeurs qui peuvent changer (dans un certain sens technique limité).

et si vous faites cela - si vous limitez la façon dont les variables peuvent changer -, vous finirez presque par accident de forcer le programmeur à écrire des programmes plus déclaratifs, car une grande partie de la programmation impérative décrit comment les variables changent, et vous ne pouvez plus fais ça! il s'avère donc que la programmation fonctionnelle - en particulier la programmation dans un langage fonctionnel - tend à donner plus de code déclaratif.

pour résumer, alors:

  • impératif et déclaratif sont deux styles de programmation opposés (les mêmes noms sont utilisés pour les langages de programmation qui encouragent ces styles)

  • la programmation fonctionnelle est un style de programmation dans lequel les fonctions deviennent très importantes et, par conséquent, les valeurs changeantes deviennent moins importantes. la capacité limitée de spécifier les changements de valeurs impose un style plus déclaratif.

donc "programmation fonctionnelle" est souvent décrite comme "déclarative".

52
andrew cooke

En un mot:

Un langage impératif spécifie une série d'instructions que l'ordinateur exécute en séquence (faites ceci, puis faites-le).

A langage déclaratif déclare un ensemble de règles sur les sorties qui doivent résulter de quelles entrées (par exemple, si vous avez A, le résultat est B). Un moteur appliquera ces règles aux entrées et donnera une sortie.

A langage fonctionnel déclare un ensemble de fonctions mathématiques/logiques qui définissent comment l’entrée est traduite en sortie. par exemple. f(y) = y * y. c'est un type de langage déclaratif.

50
mdja

Impératif: comment pour atteindre notre objectif

   Take the next customer from a list.
   If the customer lives in Spain, show their details.
   If there are more customers in the list, go to the beginning

Déclaratif: ce que nous voulons réaliser

   Show customer details of every customer living in Spain
23
Arturo Herrero

Programmation impérative désigne tout style de programmation dans lequel votre programme est structuré avec des instructions décrivant le déroulement des opérations effectuées par un ordinateur.

Programmation déclarative signifie tout style de programmation dans lequel votre programme est une description du problème ou de la solution - mais n'indique pas explicitement comment le travail sera effectué.

Programmation fonctionnelle est une programmation qui évalue les fonctions et les fonctions des fonctions ... Par programmation fonctionnelle (strictement définie), on entend la programmation en définissant des fonctions mathématiques sans effets secondaires de sorte qu'il est une forme de programmation déclarative mais ce n'est pas le seul type de programmation déclarative.

Programmation logique (par exemple dans Prolog) est une autre forme de programmation déclarative. Cela implique de calculer en déterminant si une déclaration logique est vraie (ou si elle peut être satisfaite). Le programme est généralement une série de faits et de règles - c’est-à-dire une description plutôt qu’une série d’instructions.

Réécriture de termes (par exemple, CASL) est une autre forme de programmation déclarative. Cela implique une transformation symbolique des termes algébriques. C'est complètement distinct de la programmation logique et de la programmation fonctionnelle.

21
Dafydd Rees

impératif - les expressions décrivent une séquence d'actions à effectuer (associatives)

déclaratif - les expressions sont des déclarations qui contribuent au comportement du programme (associatif, commutatif, idempotent, monotone)

fonctionnel - les expressions ont pour effet ; la sémantique soutient le raisonnement équationnel

13
dmbarbour

Programmation impérative: indiquer à la "machine" comment faire quelque chose et par conséquent ce que vous voulez qu'il se produise se produira.

Programmation déclarative: indiquez à la "machine" ce que vous souhaitez, et laissez l’ordinateur comprendre comment le faire.

Exemple d'impératif

function makeWidget(options) {
    const element = document.createElement('div');
    element.style.backgroundColor = options.bgColor;
    element.style.width = options.width;
    element.style.height = options.height;
    element.textContent = options.txt;

    return element;
}

Exemple de déclaration

function makeWidget(type, txt) {
    return new Element(type, txt);
}

Remarque: La différence n’est pas une concision, une complexité ou une abstraction. Comme indiqué, la différence est comment vs quoi.

6
yondoo

De nos jours, nouvel objectif: nous avons besoin des anciennes classifications?

Les aspects Impératif/Déclaratif/Fonctionnel étaient bons dans le passé pour classer les langages génériques, mais de nos jours tous les "grands langages" (comme Java, Python, Javascript, etc.) ont une option (généralement - frameworks ) pour exprimer avec "un autre objectif" que son principal (impératif habituel), et pour exprimer des processus parallèles, des fonctions déclaratives, des lambdas, etc.

Donc, une bonne variante de cette question est "Quel aspect est-il bon de classer les frameworks aujourd'hui?" ... Un aspect important est quelque chose que nous pouvons étiqueter "style de programmation". ..

Focus sur la fusion des données avec l'algorithme

Un bon exemple à expliquer. Comme vous pouvez lire sur jQuery sur Wikipedia ,

L'ensemble des fonctionnalités de base de jQuery - sélections d'éléments DOM, parcours et manipulation -, activé par son moteur de sélecteur (...), a créé un nouveau "style de programmation", des algorithmes de fusion et des structures de données DOM.

Donc, jQuery est le meilleur exemple (populaire) de se concentrer sur un "nouveau style de programmation", ce n'est pas seulement l'orientation d'objet, c'est " Fusing algorithmes et structures de données ". jQuery est quelque peu réactif car les feuilles de calcul, mais pas "orienté cellule", est "orienté noeud DOM" ... en comparant le principal styles dans ce contexte:

  1. Pas de fusion : dans tous les "grands langages", dans toutes les expressions fonctionnelles/déclaratives/impératives, l'habituel est "pas de fusion" des données et de l'algorithme, sauf par une certaine orientation objet, c’est un fusion dans structure algébrique stricte point de vue.

  2. Un peu de fusion : toutes les stratégies classiques de fusion, ont de nos jours un cadre qui l’utilise comme paradigme ... flux de données , - Programmation événementielle (ou anciens langages spécifiques à un domaine tels que awk et XSLT ) ... Comme la programmation avec des feuilles de calcul modernes, ce sont aussi des exemples de: programmation réactive style.

  3. Grande fusion : est "le style jQuery" ... jQuery est un langage spécifique au domaine qui se concentre sur "fusing algorithmes et - structures de données DOM ".
    PS: d’autres "langages de requête", comme XQuery, SQL (avec PL comme option d’expression impérative) sont aussi des exemples de fusion d’algorithmes de données, mais ils sont islands, sans fusion avec autres modules système ... Spring , lorsque vous utilisez find()- variantes et Spécification clauses, constitue un autre bon exemple de fusion.

4
Peter Krauss

Je pense que votre taxonomie est incorrecte. Il existe deux types opposés impératif et déclaratif. Fonctionnel est juste un sous-type de déclaratif. BTW, wikipedia affirme le même fait.

3
Rorick

La programmation déclarative est une programmation exprimant une logique intemporelle entre l'entrée et la sortie. Par exemple, en pseudocode, l'exemple suivant serait déclaratif:

def factorial(n):
  if n < 2:
    return 1
  else:
    return factorial(n-1)

output = factorial(argvec[0])

Nous définissons simplement une relation appelée "factorielle" ici et définissons la relation entre la sortie et l'entrée en tant que cette relation. Comme il devrait être évident ici, à propos de tout langage structuré permet une programmation déclarative dans une certaine mesure. Une idée centrale de la programmation déclarative est celle des données immuables. Si vous affectez une variable, vous ne le faites qu'une fois, puis plus jamais. D'autres définitions plus strictes impliquent qu'il peut n'y avoir aucun effet secondaire, ces langues sont parfois appelées "purement déclaratives".

Le même résultat dans un style impératif serait:

a = 1
b = argvec[0]
while(b < 2):
  a * b--

output = a

Dans cet exemple, nous n’avons exprimé aucune relation logique statique intemporelle entre l’entrée et la sortie, nous avons modifié manuellement les adresses mémoire jusqu’à ce que l’une d’elles conserve le résultat souhaité. Il devrait être évident que toutes les langues autorisent la sémantique déclarative dans une certaine mesure, mais ne permettent pas toutes l'impératif, certaines langues "purement" autorisant les effets secondaires et la mutation.

On dit souvent que les langages déclaratifs spécifient "ce qui doit être fait", par opposition à "comment le faire", je pense que c'est un terme impropre, les programmes déclaratifs spécifiant toujours comment on doit obtenir des entrées à la sortie, mais d'une autre manière, la relation que vous spécifiez doit être effectivement calculable (terme important, recherchez-le si vous ne le connaissez pas). Une autre approche est la programmation non déterministe , qui spécifie simplement les conditions dans lesquelles un résultat se rencontre, avant que votre implémentation n'épuise tous les chemins en essais et erreurs jusqu'à ce qu'elle le soit réussit.

Les langages purement déclaratifs incluent Haskell et Pure Prolog. Une échelle mobile de l'un à l'autre serait: Pure Prolog, Haskell, OCaml, Scheme/LISP, Python, Javascript, C--, Perl, PHP, C++, Pascall, C, Fortran, Assembly

3
Zorf

Quelques bonnes réponses ici concernant les "types" notés.

Je soumets quelques concepts supplémentaires, plus "exotiques" souvent associés à la foule de programmation fonctionnelle:

  • Langage Spécifique au Domaine ou DSL Programmation: créer un nouveau langage pour traiter le problème.
  • méta-programmation: lorsque votre programme écrit d'autres programmes.
  • Programmation évolutive: où vous construisez un système qui s'améliore continuellement ou génère successivement de meilleures générations de sous-programmes.
3
msmithgu

En un mot, plus un style de programmation met l'accent sur Quoi (faire), en faisant abstraction des détails de Comment (faire), plus ce style est considéré comme déclaratif. Le contraire est vrai pour impératif. La programmation fonctionnelle est associée au style déclaratif.

2
jchadhowell