cours/mémoire de L3.md
Oscar Plaisant 602a41e7f8 update
2024-12-25 22:30:24 +01:00

54 KiB
Raw Permalink Blame History

up:: notes mémoire de L3 #s/informatique #s/fac

Introduction

!notes mémoire de L3#^abstract

Définition et concepts importants

Définition de concepts importants

état

L'état est la capacité, pour un programme, à retenir de l'information. "State is the ability to remember information, or more precisely, to store a sequence of values in time." (L'état est la capacité à retenir de l'information, ou, plus précisément, à stocker une séquence de valeurs dans le temps) [@royProgrammingParadigmsDummies, p.14].

Il est important de noter que la présence de variables n'implique pas toujours la présence d'état. En effet, une fonction peut avoir un paramètre sans avoir nécessairement d'état. Les variables des fonctions, si elles constituent une référence à une valeur, n'impliquent pas la présence d'état.

Note: la logique combinatoire fournit la preuve qu'il est possible d'établir un système de calcul sans aucune variable ni référence, ce qui rend l'absence d'état évidente [@LogiqueCombinatoire2023].

Fonction et procédure

Les termes "fonction" et "procédure" sont, selon les contextes et les auteurs, utilisés pour désigner différentes choses.

[!cite]+ Function (computer programming) - Page In computer programming, a function, subprogram, procedure, method, routine or subroutine is a callable unit[1] that has a well-defined behavior and can be invoked by other software units to exhibit that behavior. ^GNQR9GC2aRIAPAJ6Eg5383243

Par exemple, le livre "Structure and interpretation of computer programs" [@abelsonStructureInterpretationComputer1996] fournit la distinction suivante : les fonctions sont l'aspect mathématique du concept et sont définies en déclarant "ce qu'elle est" , en donnant des propriétés de cette fonction (une définition déclarative, voir mémoire de L3#programmation déclarative). Les procédures sont l'aspect programmatique du concept, et sont définies en déclarant "comment elle doit faire", en décrivant comment elle doit s'exécuter 1.

Cependant, certains auteurs utilisent le terme procedure même pour parler du concept théorique et mathématique (qui se rapproche du lambda-calcul) 2.

Nous utiliserons donc principalement le terme fonction, avec les définitions suivantes :

[!definition] fonction Une fonction est l'encapsulation d'un ensemble d'instructions. Une fonction peut posséder des paramètres qui peuvent influencer son exécution. Ces paramètres sont des valeurs ou des références qui sont données ("passées en argument") lors de l'appel de cette fonction. Une fonction peut retourner une valeur. Une fonction peut être appelée plusieurs fois et à plusieurs endroits, ce qui la rend réutilisable dans plusieurs contextes.

[!definition] fonction pure Une fonction pure est une fonction déterministe, c'est-à-dire que les mêmes arguments donnent toujours la même valeur de retour. Une fonction pure est une fonction sans effet de bord, c'est-à-dire qu'elle ne modifie pas l'état du système (en dehors de son champ local propre, dont la durée de vie est limitée).

Effet de bord

Un effet de bord est la modification d'état par une fonction. Du point de vue du développeur, cela arrive lorsqu'une fonction effectue des modifications en dehors de son propre corps. Cela peut être fait en utilisant des références ou des constructions particulières du langage.

Voici des exemples de mécanismes qui permettent des effets de bord 3:

  • Les variables globales : en permettant à toutes les fonctions d'accéder à un même champ de mémoire, les variables globales leur donnent la possibilité de modifier l'état du système
  • les variables statiques locales : en permettant aux objets d'une même classe de partager une variable, on leur permet de générer des effets de bord contrôlés
  • les arguments mutables (les arguments passés par référence) : ce mécanisme permet de répercuter la modification d'un paramètre en modification de l'argument, ce qui permet à la fonction de modifier une valeur qui lui a été passée en argument. Cela constitue un effet de bord

Fermeture

Une fermeture (de l'anglais closure) est une fonction à laquelle on attache l'environnement local de l'endroit où elle a été définie 4 5. Cela permet à cette fonction d'accéder aux valeurs et aux références de cet environnement local, même si elle est appelée depuis un autre contexte (dans un autre champ local) 5. Du point de vue du développeur, cela signifie que l'exécution d'une fermeture soit le même que si les instructions étaient exécutées "à l'endroit" (dans le contexte où elle a été définie) la fermeture a été créée 6.

Un avantage considérable des fermetures est qu'elles permettent d'accéder aux valeurs et références d'un environnement local qui n'existe plus (car il a été libéré de la pile d'exécution) 7.

Qu'est-ce qu'un paradigme ?

Un paradigme de programmation est une façon d'approcher la programmation et de formuler les problèmes et leur formalisation dans un langage de programmation 8. En particulier, un paradigme fournit et détermine comment un développeur doit voir un programme. La notion de paradigme est notamment à dissocier de celles de méthode ou bien de design patterns, qui décrivent comment traiter des problèmes spécifiques et reconnus, et comment aboutir à une solution conceptuelle [@ParadigmeProgrammation2023]. Un paradigme est un concept plus "haut niveau", c'est-à-dire plus abstrait : chaque paradigme supporte un ensemble particulier de concepts (cohérents entre eux), qui peuvent être hérités d'une théorie mathématique, de principes fondamentaux, ou bien d'une vision sur ce que doit être la programmation 9.

Un paradigme de programmation est souvent principalement décrit par les concepts qu'il implémente ou non 10. C'est notamment cette approche qu'emploie la taxonomie des paradigmes de programmation (référence à une annexe) [@TaxonomiePrincipauxParadigmes].

Cependant, J.Huges, dans son article "Why Functional Programming Matters" [@hughesWhyFunctionalProgramming1989, p.1], fustige le fait que certains paradigmes (particulièrement la programmation fonctionnelle ref et la programmation structurée ref) sont trop fréquemment définis en termes des fonctionnalités qu'ils n'implémentent pas, ou des contraintes qu'ils posent 11. Cela est problématique, car l'absence d'une fonctionnalité ne peut pas expliquer pourquoi un paradigme serait plus intéressant dans certains cas 12. L'auteur insiste donc sur le fait que les paradigmes devraient être définis en fonction des avantages structurels qu'ils apportent pour résolution de certains types de problèmes.

C'est pour cette raison que, dans notre définition des différents paradigmes, nous chercherons à expliquer à la fois les principes fondamentaux de chaque paradigme, mais également à montrer brièvement pourquoi ceux-ci sont intéressants, c'est-à-dire répondre à la question "en quoi ce paradigme apporte-t-il quelque chose". Cela constituera une première partie de réponse à notre problématique.

Description de quelques paradigmes

taxonomie des paradigmes de programmation

Programmation impérative

La programmation impérative est un paradigme de programmation dans lequel le contrôle de flot d'exécution est explicite. Cela signifie que le programme spécifie pas à pas la marche à suivre pour obtenir le bon résultat. En programmation impérative, chaque étape modifie l'état global du système 13.

Programmation déclarative

La programmation déclarative est un paradigme de programmation dans lequel la définition des programmes se fait en déclarant la forme du résultat plutôt que la manière l'obtenir (comme on le fait en mémoire de L3#programmation impérative) Le développeur ne s'occupe donc pas de l'exécution, mais plutôt de comment spécifier le résultat. Le contrôle du flot d'exécution est implicite. En cela, la programmation déclarative s'oppose à la programmation impérative 14.

Un avantage évident de la programmation déclarative est qu'elle libère le programmeur de certaines charges mentales, notamment celle de spécifier l'ordre d'exécution, le flot de contrôle de l'exécution. Cela rend le paradigme déclaratif plus pratique pour le développeur (plus haut niveau), puisqu'il ne requiert pas de s'occuper de certains détails qui n'influent pas sur le sens du programme 15.

Programmation fonctionnelle

La programmation fonctionnelle est un paradigme de programmation dans lequel les programmes sont exprimés comme des arbres d'expressions.

Le contrôle du flot d'exécution est donc fait en combinant des fonctions 16: la fonction principale prend en argument l'entrée du problème, puis elle est définie à partir d'autres fonctions, qui sont elles-mêmes définies à partir de fonctions, et ce, jusqu'à ce que les fonctions à la base de la définition (les feuilles de l'arbre d'expressions) soient des primitives du langage, ou bien des constantes 17. Cela distingue la programmation fonctionnelle d'autres paradigmes, notamment en programmation impérative, où l'état est beaucoup plus utilisé, notamment pour le contrôle du flot d'exécution.

Ces propriétés rapprochent beaucoup la programmation fonctionnelle des mathématiques 17.

Voici une définition de la programmation fonctionnelle : "Functional programming is about writing pure functions, about removing hidden inputs and outputs as far as we can, so that as much of our code as possible just describes a relationship between inputs and outputs." [@jenkisWhatFunctionalProgramming2015]. Cette définition met l'accent sur le fait que la programmation fonctionnelle cherche à décrire, le plus possible, les programme comme des relations entre une entrée et une sortie, définie par des fonctions. L'auteur appelle "entrées et sorties cachées" ("hidden inputs and outputs") toute référence qui ne passe pas par les paramètres ou le retour des fonctions, ce qui inclut notamment les effets de bord.

Les fonctions d'ordre supérieur sont centrales en programmation fonctionnelle. Les fonctions d'ordre supérieur sont des fonctions qui prennent en argument, ou renvoient d'autres fonctions. Ces fonctions d'ordre supérieur (aussi appelées "fonctionnelles") permettent donc de modifier ou combiner entre elles d'autres fonctions 18.

Pour que les fonctions d'ordre supérieur existent, il est nécessaire que les fonctions soient des citoyens de première classe, c'est-à-dire des entités traitées comme des valeurs du langage. Il est également nécessaire que le langage implémente les mémoire de L3#Fermeture, le cas échéant il serait impossible d'implémenter certaines fonctions d'ordre supérieur. La programmation fonctionnelle privée des fermetures (et donc des fonctions d'ordre supérieur) s'appelle la programmation fonctionnelle de premier ordre (ref à la taxonomie en annexe).

Programmation fonctionnelle pure

La programmation fonctionnelle pure (parfois appelée simplement programmation fonctionnelle) est un paradigme dans lequel toutes les fonctions sont pures, c'est-à-dire qu'il n'existe pas d'état 19.

programmation structurée

La programmation structurée peut être définie, du point de vue théorique, comme un paradigme dans lequel le contrôle du flot se fait en utilisant des instructions de contrôle du flot d'exécution particulières (des structures de sélection et d'itération), et qui sont sous la forme de blocks 20. Les structures de sélection sont des structures particulières qui permettent de choisir quel groupe d'instruction sera exécuté en fonction de l'état du programme 21. Les structures d'itération sont des instructions qui exécutent répétitivement un block jusqu'à ce que le programme atteigne un certain état, ou bien que certaines opérations aient été appliquées sur chaque élément d'une collection 22.

Il est important de voir que le but de la programmation structurée est de produire des programmes plus clairs et de meilleure qualité, de par la modularité induite par la structuration du programme 23.

Une autre définition de la programmation structurée est une façon de concevoir les programmes

"In the first phase, that of top-down design, or stepwise refinement, the problem is decomposed into a very small number of simpler subproblems." [@floydParadigmsProgramming1979a, p.1]

"The second phase of the structured programming paradigm entails working upward from the concrete objects and functions of the underlying machine to the more abstract objects and functions used throughout the modules produced by the top-down design. [...] This approach is reffered to as the method of levels of abstraction, or of information hiding." [@floydParadigmsProgramming1979a, pp. 1-2]

"The absence of gotos and so on, has very little to do with this [the advantages strutcured programming, especially modularity]. It helps with 'programming in the small', whereas modular design helps with 'programming in the large'. Thus one can enjoy the benefits of structured programming in FORTRAN or assembly language, even if it is a little more work." [@hughesWhyFunctionalProgramming1989, p.2]

Programmation concurrente

La programmation concurrente permet de gérer des programmes avec plusieurs ensembles d'instructions dont l'exécution doit être indépendante. En programmation impérative stricte, l'ordre des instructions définit leur ordre d'exécution, ce qui les rend interdépendantes. On dit alors que ces instructions sont séquentielles. La programmation concurrente introduit le concept de concurrence, lorsque deux parties d'un programme n'ont pas de dépendance l'une avec l'autre 24.

"Le monde réel est concurrent : il consiste en des activités qui évoluent indépendamment" ("The real world is concurrent: it consists of activities that evolve independently." [@royProgrammingParadigmsDummies, p.25]).

Les langages multiparadigmes

Il existe beaucoup de langages qui implémentent plusieurs paradigmes de programmation [@ComparisonMultiparadigmProgramming2024]. Ces langages sont appelés langages multiparadigmes.

Par exemple, le langage Prolog implémente à la fois la programmation logique et la programmation impérative 25. Un autre exemple peut être trouvé lorsque l'on ajoute une librairie de résolution de contraintes à un langage de programmation. Le paradigme de programmation par contraintes est alors ajouté au langage hôte, qui peut, par exemple, être un langage impératif et orienté objet 26.

Nous verrons l'avantage des langages de programmation multiparadigmes dans la section mémoire de L3#diversité des approches

Intérêt intrinsèque des paradigmes

On comprend par leur simple définition un premier intérêt des paradigmes de programmation : ils permettent d'exprimer des concepts différents, de donner des approches différentes sur la programmation.

Définition de la puissance d'expression

La puissance d'expression (ou expressivité) d'un langage est la quantité et la diversité d'idées qu'il peut représenter ou communiquer 2728.

On distingue deux sens du terme. D'un côté, l'expressivité théorique, qui se concentre sur la possibilité théorique d'exprimer une idée dans un langage, indépendamment de la difficulté pour exprimer cette idée. De l'autre côté, l'expressivité pratique, qui se concentre sur la concision et la facilité d'expression de ces idées 29.

Expressivité au sens formel

La puissance d'expression au sens formel (ou expressivité formelle) est mesurée en regardant l'ensemble des idées qu'un langage peut exprimer. Ce concept d'expressivité formelle est surtout utile en mathématiques ou en informatique théorique (notamment dans la théorie des langages formels) 30

Pour un langage de programmation, il est presque indispensable d'être aussi expressif qu'une machine de Turing (Turing-complets) (ou un autre modèle de calcul équivalent), car cela est la condition nécessaire et suffisante pour qu'il puisse exprimer les problèmes calculables (par définition).

Il existe tout de même des langages qui n'ont pas la même expressivité formelle. On peut notamment citer les langages de description de données, dont le but est de représenter des données organisées (par exemple, les langages XML, JSON, YAML...), ou bien les langages de description d'ontologies, qui servent à représenter de façon informatique certains types d'ontologie. Notamment, OWL2 EL et OWL2 RL sont deux langages de description d'ontologies qui n'ont pas la même expressivité formelle : OWL2 EL n'implémente pas certains concepts qui peuvent pourtant être exprimés dans OWL2 RL 31.

Cependant, ces langages ne sont généralement pas qualifiés de "langages de programmation", puisqu'ils sont incapables d'exprimer un programme (c'est-à-dire des instructions exécutables), mais expriment seulement des données.

Il existe également des langages de programmation qui ne sont pas Turing-complets (par exemple, le langage G-code, dans certaines implémentations 32), mais ces langages ne sont pas utilisés pour résoudre des problèmes de programmation : ils sont utilisés à des fins théoriques, ou pour des applications particulières (par exemple, le langage G-code est utilisé pour commander des machines à commande numérique 33).

Expressivité au sens pratique

L'expressivité pratique est la diversité et la quantité d'idées qu'un langage de programmation peut exprimer facilement. Dans ce sens de l'expressivité, la facilité d'exprimer une idée est primordiale. Comme il est dit dans la section mémoire de L3#Expressivité au sens formel, la plupart des langages de programmation ont la même expressivité théorique. Cependant, il n'est pas suffisant pour l'expressivité pratique qu'une idée soit théoriquement exprimable : il est nécessaire qu'il soit aisé de le faire, que le langage implémente des fonctionnalités directement. Il est, par exemple, possible de faire de la programmation structurée (voir : mémoire de L3#programmation structurée) ou de la programmation fonctionnelle (voir : mémoire de L3#programmation fonctionnelle) dans un langage qui ne supporte pas nativement ces paradigmes (par exemple le langage assembleur). En général, pour tout concept x implémenté par un langage de programmation A, il sera toujours possible de créer un équivalent de x dans un langage B qui ne l'implémente pas nativement (à condition que B soit Turing Complet). Cependant, l'expressivité au sens pratique ne prend pas en compte cette possibilité, et ne considère que les idées directement (ou presque directement) implémentées et exprimables dans un langage.

L'expressivité pratique d'un langage est donc très liée aux paradigmes qu'il implémente. On pourrait même définir l'expressivité au sens pratique d'un langage comme la quantité de paradigmes qu'il implémente.

Compromis entre expressivité et analysabilité

Plus un langage est expressif, plus il est complexe de l'analyser mathématiquement. Plus un langage est puissant expressivement au sens formel, plus il devient difficile (et impossible) de démontrer certains théorèmes sur ce formalisme 34. Cela est vrai également pour l'expressivité au sens pratique : "le fait d'éviter certaines techniques peut permettre de rendre plus aisée la démonstration de théorèmes sur la correction d'un programme -- ou simplement la compréhension de son fonctionnement -- sans limiter la généralité du langage de programmation." [@ParadigmeProgrammation2023].

Exemple de compromis : automates et grammaires

Les automates à pile et les machines de Turing forment un exemple de compromis entre analysabilité et expressivité formelle. Les automates à pile reconnaissent les langages non contextuels 35. Les machines de Turing reconnaissent les langages contextuels 36. Or, les langages non contextuels sont strictement inclus dans les langages récursivement énumérables 37 . On peut donc conclure que les machines de Turing ont un pouvoir d'expression formel supérieur à celui des automates à pile.

Cependant, si on pose le problème de l'appartenance d'un mot à un langage donné. Ce problème est décidable pour tous les langages non contextuels 38. Pourtant, ce problème est indécidable pour les machines de Turing 39.

On voit donc que les machines de Turing sont un formalisme plus expressif (certains concepts exprimés par des machines de Turing ne sont pas exprimables par des automates à pile) mais moins analysable (certains problèmes sont décidables sur les automates à pile, mais pas sur les machines de Turing).

Exemple de compromis : le non-déterminisme

Un langage de programmation est dit non déterministe lorsque son exécution ne dépend pas uniquement des spécifications du programme, c'est-à-dire que les spécifications laissent un choix lors de l'exécution du programme 40. Le non-déterminisme est donc problématique, puisqu'il peut amener à créer des programmes dont le résultat est inattendu ou incertain : il rend les programmes moins analysables. Ce pendant, certains paradigmes qui peuvent exprimer du non-déterminisme restent utiles pour modéliser certains problèmes (par exemple, la programmation concurrente, voir mémoire de L3#Programmation concurrente) 41.

Une critique

C'est pourquoi certaines fonctionnalités, certains paradigmes, comme le non-déterminisme et les paradigmes qui l'impliquent, devraient être utilisés seulement si cela est nécessaire 42.

Implications sur la diversité des paradigmes

Nous avons montré qu'il est nécessaire de faire des choix dans les concepts qu'implémente un paradigme, afin de faire un compromis entre analysabilité et expressivité. Cela donne une justification à l'existence de différents paradigmes : l'implémentation ou non de certains concepts à de réelles influences, non seulement sur l'expressivité des langages, mais également sur les propriétés de celui-ci (comme le déterminisme). Il est donc important de pouvoir choisir quels concepts utiliser selon les situations, afin de trouver le meilleur compromis entre expressivité et analysabilité.

Paradigmes dans l'apprentissage

Importance des paradigmes dans l'apprentissage

Les paradigmes de programmation jouent un rôle dans l'apprentissage d'un langage. Théoriquement les mêmes idées pourraient être représentées indépendamment du paradigme, mais le paradigme fournit un modèle de pensée, une approche, un cadre. Ces modèles de pensée sont utiles pour apprendre, car le fait d'avoir en tête des modèles, des idées générales sur la façon d'envisager un programme, permet d'apprendre plus aisément 43. Les paradigmes sont encore plus importants du point de vue de l'enseignant, qui doit identifier clairement les paradigmes qu'il enseigne pour pouvoir transmettre efficacement les concepts de la programmation 44. Le fait d'apprendre des paradigmes, des modèles mentaux, permet également de se détacher du langage de programmation particulier, et d'acquérir des connaissances générales, qui restent valides même lorsque l'on change de langage. Maîtriser un paradigme est utile pour tous les langages qui implémentent ce paradigme44.

Avantages de la diversité

On peut se demander s'il est intéressant d'apprendre plusieurs paradigmes au travers d'un ou plusieurs langages de programmation, si cette diversité des paradigmes est utile pour l'apprentissage.

Au fil du temps, à force de lire et travailler avec du code, nos compétences en programmation augment45 et l'on mémorise beaucoup de cas qui nous aideront à résoudre des problèmes plus intuitivement et à construire une bibliothèque mentale de modèles46 que n'aura pas un développeur débutant. Les sciences cognitives montrent que la différence principale entre un expert et un débutant n'est pas sa capacité à raisonner, mais plutôt à reconnaître des motifs qu'il a déjà vus 47. Cela montre l'importance de se construire une telle "bibliothèque mentale de modèles".

Conclusion sur les paradigmes pour l'apprentissage

Dans le contexte de l'apprentissage de la programmation, les paradigmes présentent plusieurs intérêts :

  • fournir des modèles mentaux à ceux qui apprennent, afin de mieux envisager la programmation
  • fournir des abstractions et des connaissances utiles indépendamment du langage.
  • fournir des abstractions, des motifs reconnaissables, qui finissent par former une "bibliothèque mentale de modèles"

Paradigmes pour la résolution de problèmes

Les paradigmes fournissent un cadre pour la pensée

La définition même de paradigme explique déjà en partie l'existence des différents paradigmes : un paradigme donne une façon d'envisager la programmation. Comme il existe de nombreux types de problèmes, de nombreuses situations à modéliser, il semble normal que de nombreux paradigmes existent pour donner les concepts et outils nécessaires afin d'implémenter efficacement des solutions à ces problèmes.

L'existence de nombreux paradigmes de programmation peut donc être justifiée par diversité des problèmes rencontrés : chaque paradigme permet de répondre à une classe de problèmes précis. Par exemple, la programmation concurrente (voir : mémoire de L3#Programmation concurrente) permet de modéliser des situations dans lesquelles deux événements indépendants évoluent en même temps et indépendamment.

L'efficacité peut ici avoir deux sens : l'efficacité pour l'humain, c'est-à-dire l'aisance avec laquelle le développeur pourra implémenter une solution à son problème; et l'efficacité lors de l'exécution (efficacité pour la machine), qui dépend du temps et de l'espace mémoire nécessaires à l'exécution du programme. La nécessité de faire des compromis entre expressivité et analysabilité décris plus haut (voir mémoire de L3#compromis entre expressivité et analysabilité) peut avoir pour conséquence la nécessité de faire des compromis entre efficacité pour l'humain et efficacité pour la machine. En effet, une plus grande efficacité pour l'humain peut être atteinte par une plus grande expressivité (théorique, mais surtout pratique); or, nous avons vu que cela pouvait mener à une moins grande analysabilité du langage, ce qui implique notamment que moins d'optimisation seront possibles lors de l'exécution d'un programme.

Avantages des langages multiparadigmes

Lors de la résolution de problèmes, il peut être utile d'avoir de nombreux modèles à disposition, afin de pouvoir choisir celui qui correspond le mieux au problème actuel. Si ces modèles sont directement implémentés dans notre langage de programmation (s'il supporte les bons paradigmes), la résolution de notre problème sera beaucoup plus aisée. "A language should ideally support many concepts in a well-factored way, so that the programmer can choose the right concepts whenever they are needed without being encumbered by the others." : Un langage devrait, dans l'idéal, intégrer de manière cohérente un grand nombre de paradigmes, pour permettre au développeur de choisir quels concepts il souhaite utiliser, sans être encombré par les autres [@royProgrammingParadigmsDummies p.10].

Certains langages ne nécessitent pas un grand pouvoir d'expression, car ils répondent à un besoin spécifique (voir mémoire de L3#Expressivité au sens formel). Cependant, la plupart des langages ont pour but de pouvoir résoudre une grande diversité de problèmes, et il est donc nécessaire qu'ils permettent de décrire et manipuler aisément un grand nombre de concepts.

créer un paradigme pour chaque type de problème

Le principe de l'extension créative (de l'anglais creative extension principle) est une méthode qui permet de créer de nouveaux paradigmes. Elle permet de trouver et d'organiser des concepts utiles à la programmation, pour réellement former un paradigme 48.

L'extension créative part de la constatation qu'un problème nécessite des modifications envahissantes (des modifications dans l'ensemble des contextes du programme) pour être résolu. Il est alors nécessaire de comprendre cette difficulté (pourquoi cette modification devient-elle envahissante ?), et de trouver un concept plus général, plus fondamental, qui résout cette difficulté, c'est-à-dire qui permet d'éliminer ces modifications envahissantes pour retrouver un programme simple 49.

Par exemple, si l'on cherche à modéliser plusieurs activités indépendantes dans un langage purement impératif, il faut implémenter soi-même plusieurs piles d'exécution, ainsi qu'un ordonnanceur... Les modifications impliquées par ce problème sont envahissantes. Cette complexité peut être évitée si notre langage implémente un concept (et donc un paradigme) : la concurrence (voir mémoire de L3#Programmation concurrente) 50. La même logique peut s'appliquer à la gestion d'erreurs dans un programme. Si l'on veut être capable de gérer les erreurs dans un programme, il faut ajouter des conditions dans le corps de chaque fonction, pour que chacune retourne le code d'erreur jusqu'à l'appel initial. Les modifications impliquées par ce problème sont envahissantes. Cette complexité peut être évitée si notre langage implémente un concept (et donc un paradigme) : les exceptions 51.

Floyd, dans son papier "The Paradigms of Programming", explique une méthode similaire qui lui permet de créer de nouveaux paradigmes : lorsqu'il résout un problème complexe, il essaie d'extraire l'essence de sa solution, de la simplifier pour obtenir une solution aussi directe que possible. Il cherche ensuite une règle générale qui lui permettrait de résoudre des problèmes semblables. Cette règle, s'il la trouve, peut être le concept fondateur d'un nouveau paradigme 52.

On peut donc voir chaque paradigme comme la réponse à un problème particulier, à une situation qui serait complexe à modéliser sans ce paradigme.

Il serait même pertinent, de ce point de vue, d'encourager la création de nouveaux paradigmes dès que l'on trouve des problèmes nouveaux qui sont complexes à résoudre avec les paradigmes existants.

Les paradigmes comme outil pour la pensée

Connaître un système de calcul ne permet pas d'immédiatement tout connaître sur son champ d'expressivité Notamment :

  • connaître un système de calcul ne permet pas (toujours) de connaître l'ensemble des problèmes décidables de ce système

Connaître un langage de programmation ne permet pas de savoir immédiatement comment résoudre tous les problèmes que l'on risque de rencontrer. Par exemple, la syntaxe des langages dérivés de LISP est très simple, et peut être apprise en peu de temps. Cependant, connaître la syntaxe complète et le fonctionnement d'un langage ne permettra pas de résoudre tous les problèmes : il est également nécessaire d'être capable de "faire le lien" entre un problème et son expression dans un langage de programmation. C'est ce lien que les paradigmes de programmation permettent de faire. Plus précisément, les paradigmes permettent de faire le lien entre un problème et une solution théorique, un modèle conceptuel qui permet ensuite d'implémenter une solution.

On peut notamment opposer les paradigmes et les méthodes. Une méthode permet de convertir en programme des problèmes déjà reconnus dans le cadre d'un paradigme, d'un écosystème. La méthode ne s'occupe pas de fournir une solution à un problème, ni un modèle pour ce problème, mais permet de convertir cette solution conceptuelle, ce modèle abstrait, en programme dans un langage particulier. Au contraire, les paradigmes explicitent plutôt quelle vision le développeur doit avoir, et quels concepts il peut utiliser pour construire son modèle du problème. Un paradigme donne donc un cadre pour modéliser un problème donné.

La figure (figref) montre les différentes étapes lorsque l'on est confronté à un problème :

  1. Résoudre le problème : trouver une idée de solution, et construire conceptuellement un modèle qui permet de résoudre notre problème. Ce sont les paradigmes qui nous permettent de faire cela, en donnant une vision sur ce qu'est un programme, et en fournissant des concepts utiles.
  2. Designer le programme : implémenter concrètement le programme dans un langage de programmation. Ce sont des méthodes, par exemple des design patterns, qui guide le développeur dans cette étape, en lui permettant de convertir des problèmes reconnus en programme dans un langage.
  3. Exécuter le programme : cette étape est réalisée par un compilateur ou un interpréteur.
  4. Interpréter les résultats : Pour que les données de sortie du programme deviennent véritablement de la connaissance, il faut leur attacher du sens et un contexte. Il faut pour cela qu'un être humain les interprète. Les statistiques fournissent notamment des outils pour interpréter des séries de données.

!paradigme_methode_execution_interprétation.excalidraw

Les paradigmes de programmations peuvent donc être vus comme un outil pour la pensée, qui permet de traduire un problème en une pré-solution, en un modèle conceptuel, en fournissant une vision sur la programmation, des modèles mentaux et des concepts utiles.

Conclusion

En fournissant un modèle pour penser les programmes informatiques, les paradigmes de programmation permettent à la fois d'améliorer l'apprentissage et la résolution de problèmes. En effet, l'abstraction fournie par les langages est utile à l'enseignement de la programmation (voir : mémoire de L3#Paradigmes dans l'apprentissages). Les divers concepts fournis par les différents paradigmes permettent également de modéliser au mieux les différents problèmes. Pour un programmeur, avoir à sa disposition un grand nombre de paradigmes permet alors de résoudre plus simplement une plus grande variété de problèmes (voir : mémoire de L3#Paradigmes pour la résolution de problèmes#Les paradigmes fournissent un cadre pour la pensée. On comprend notamment, dans ce contexte, l'intérêt particulier des langages multiparadigmes, qui laissent au développeur le choix d'utiliser ou non certains concepts selon ses besoins, mais sans avoir à changer de langage de programmation (voir : mémoire de L3#Paradigmes pour la résolution de problèmes#avantages des langages multi-paradigme). On peut par ailleurs voir les paradigmes comme résultant de la nécessité de résoudre certaines classes de problèmes. Un paradigme serait alors à créer pour chaque nouveau type de problème (voir : mémoire de L3#Paradigmes pour la résolution de problèmes#créer un paradigme pour chaque type de problème). Finalement, on peut comprendre le rôle général des paradigmes dans la résolution de problèmes : permettre la traduction des spécifications et enjeux d'un problème en un modèle conceptuel, en une idée de solution qui est entendable par le développeur (voir : mémoire de L3#Paradigmes pour la résolution de problèmes#Les paradigmes comme outil pour la pensée ).

Toutes ces raisons justifient l'existence des nombreux paradigmes de programmation, et encouragent même à en créer de nouveaux.

Annexes

contre la distinction entre les paradigmes

La distinction entre les différents paradigmes n'est pas toujours claire : beaucoup de langages sont mémoire de L3#les langages multi-paradigmes, et certains paradigmes peuvent être utilisés dans presque tous les langages (par exemple, la programmation structurée ref)

Certains auteurs considèrent que les paradigmes ne sont pas fondamentalement différents (voir : mémoire de L3#Au sens formel), mais plutôt que les paradigmes sont des courants de pensée, des traditions dans la programmation, rattachées à des communautés 53.

Greg Michaelson critique la distinction des paradigmes, en expliquant que, lorsqu'on les analyse profondément, les paradigmes sont en fait proches entre eux 54.

footnotes

Chaque paradigme permet d'avoir une vision différente d'un problème, si un problème nous parait trop complexe à résoudre avec un paradigme, un autre permettra certainement de résoudre plus simplement ce problème. Le fait de connaître une variété de paradigmes de programmation pourra aider55 le développeur, en lui permettant de choisir le plus approprié face aux nouveaux problèmes auquel il devra faire face. D'où l'utilité de voir plusieurs paradigmes de programmation ceux-ci nous permettent d'aborder un problème sous différents angles de vue afin de choisir le plus adapté à nos besoins. De plus si l'évolution générale de l'art de la programmation exige la continuation de l'invention et l'élaboration de nouveau paradigmes, les développeurs devront étendre leur répertoire de paradigmes56.


  1. "The contrast between function and procedure is a reflection of the general distinction between describing properties of things and describing how to do things, or, as it is sometimes referred to, the distinction between declarative knowledge and imperative knowledge. In mathematics we are usually concerned with declarative (what is) descriptions, whereas in computer science we are usually concerned with imperative (how to) descriptions." [@abelsonStructureInterpretationComputer1996, p.28] ↩︎

  2. par exemple, Fellesein dans cette expression : "(let x be v in e) is expressible as (apply (procedure x e) v)" [@felleisenExpressivePowerProgramming1990, p.135] ↩︎

  3. "Par exemple, les fonctions qui modifient une variable locale statique, une variable non locale ou un argument mutable passé par référence, les fonctions qui effectuent des opérations d'entrées-sorties ou les fonctions appelant d'autres fonctions à effet de bord" [@EffetBordInformatique2023] ↩︎

  4. "From an implementation viewpoint, a closure combines a procedure with its external references (the references it uses at its definition)." [@royProgrammingParadigmsDummies, p.24] ↩︎

  5. "Dans un langage de programmation, une fermeture ou clôture (en anglais : closure) est une fonction accompagnée de son environnement lexical. L'environnement lexical d'une fonction est l'ensemble des variables non locales qu'elle a capturées, soit par valeur (c'est-à-dire par copie des valeurs des variables), soit par référence (c'est-à-dire par copie des adresses mémoires des variables)[1]. Une fermeture est donc créée, entre autres, lorsqu'une fonction est définie dans le corps d'une autre fonction et utilise des paramètres ou des variables locales de cette dernière." [@FermetureInformatique2024] ↩︎

  6. From the programmers viewpoint, a closure is a “packet of work”: a program can transform any instructions into a closure at one point in the program, pass it to another point, and decide to execute it at that point. The result of its execution is the same as if the instructions were executed at the point the closure was created. [@royProgrammingParadigmsDummies, p.24] ↩︎

  7. "Une fermeture peut être passée en argument d'une fonction dans l'environnement où elle a été créée (passée vers le bas) ou renvoyée comme valeur de retour (passée vers le haut). Dans ce cas, le problème posé alors par la fermeture est qu'elle fait référence à des données qui auraient typiquement été allouées sur la pile d'exécution et libérées à la sortie de l'environnement. Hors optimisations par le compilateur, le problème est généralement résolu par une allocation sur le tas de l'environnement." [@FermetureInformatique2024] ↩︎

  8. "Le paradigme de programmation est la façon (parmi d'autres) d'approcher la programmation informatique et de formuler les solutions aux problèmes et leur formalisation dans un langage de programmation approprié. Ce n'est pas de la méthodologie contenant une méthode ; cette dernière organise le traitement des problèmes reconnus dans l'écosystème concerné pour aboutir à la solution conceptuelle et programme exécutable." [@ParadigmeProgrammation2023] ↩︎

  9. "A programming paradigm is an approach to programming a computer based on a mathematical theory or a coherent set of principles." [@royProgrammingParadigmsDummies] ↩︎

  10. "Each paradigm supports a set of concepts that makes it the best for a certain kind of problem. For example, object-oriented programming is best for problems with a large number of related data abstractions organized in a hierarchy. Logic programming is best for transforming or navigating complex symbolic structures according to logical rules. Discrete synchronous programming is best for reactive problems, i.e., problems that consist of reactions to sequences of external events." [@royProgrammingParadigmsDummies, p.10] ↩︎

  11. "It says a lot about what functional programming is not [...] but not much about what it is." [@hughesWhyFunctionalProgramming1989, p.1] ↩︎

  12. "It is a logical impossibility to make a language more powerful by ommitting features, no matter how bad they may be" [@hughesWhyFunctionalProgramming1989, p.1] ↩︎

  13. "Control flow in imperative programming is explicit: commands show how the computation takes place, step by step. Each step affects the global state of the computation." [@toalProgrammingParadigms] ↩︎

  14. "Control flow in declarative programming is implicit: the programmer states only what the result should look like, not how to obtain it." [@toalProgrammingParadigms] ↩︎

  15. "A programming language is low level when its programs require attention to the irrelevant." [@perlisSpecialFeatureEpigrams1982] ↩︎

  16. "In functional programming, control flow is expressed by combining function calls, rather than by assigning values to variables" [@toalProgrammingParadigms] ↩︎

  17. "Functional programming is so called because a program consists entirely of functions. The main program itself is written as a function which recieves the program's input as its argument and delivers the program's output as its result. Typically the main function is defined in terms of other functions, which in turn are defined in terms of still more functions, until at the bottom level the functions are language primitives. These functions are much like ordinary mathematical functions, and in this paper will be defined by ordinary equations." [@hughesWhyFunctionalProgramming1989, p.1] ↩︎

  18. "En mathématiques et en informatique, les fonctions d'ordre supérieur sont des fonctions qui ont au moins une des propriétés suivantes : elles prennent une ou plusieurs fonctions en entrée ; elles renvoient une fonction." [@FonctionOrdreSuperieur2023] ↩︎

  19. La logique combinatoire est un système de calcul dans lequel toutes les fonctions sont pures (il n'y a que des fonctions d'ordre supérieur dans ce système) [@LogiqueCombinatoire2023] ↩︎

  20. "Structured programming is a programming paradigm aimed at improving the clarity, quality, and development time of a computer program by making extensive use of the structured control flow constructs of selection (if/then/else) and repetition (while and for), block structures, and subroutines." [@StructuredProgrammingWikipedia] ↩︎

  21. "'Selection'; one or a number of statements is executed depending on the state of the program. This is usually expressed with keywords such as if..then..else..endif. The conditional statement should have at least one true condition and each condition should have one exit point at max." [@StructuredProgrammingWikipedia] ↩︎

  22. "'Iteration'; a statement or block is executed until the program reaches a certain state, or operations have been applied to every element of a collection. This is usually expressed with keywords such as while, repeat, for or do..until. Often it is recommended that each loop should only have one entry point (and in the original structural programming, also only one exit point, and a few languages enforce this)." [@StructuredProgrammingWikipedia] ↩︎

  23. "The most important difference between structured and unstructured programs is that the former are designed in a modular way. Modular design brings great productivity improvements. First of all, small modules can be coded quickly and easily. Secondly, general purpose modules can be reused, leading to faster development of subsequent programs. Thirdly, the modules of a program can be tested independently, helping to reduce the time spent debugging." [@hughesWhyFunctionalProgramming1989, p.2] ↩︎

  24. "For example, consider a program that consists of instructions executing one after the other. The instructions are not independent since they are ordered in time. To implement independence we need a new programming concept called concurrency. When two parts do not interact at all, we say they are concurrent.3 (When the order of execution of two parts is given, we say they are sequential.)" [@royProgrammingParadigmsDummies, p.25] ↩︎

  25. "Prolog: The first paradigm is a logic programming engine based on unification and depth-first search. The second paradigm is imperative: the assert and retract operations which allow a program to add and remove program clauses." [@royProgrammingParadigmsDummies, p.18] ↩︎

  26. "Solving libraries (e.g., Gecode): The first paradigm is a solver library based on advanced search algorithms, such as Gecode. The second paradigm is added by the host language, e.g., C++ and Java support object-oriented programming." [@royProgrammingParadigmsDummies, p.18] ↩︎

  27. "In computer science, the expressive power (also called expressiveness or expressivity) of a language is the breadth of ideas that can be represented and communicated in that language." [@ExpressivePowerComputer2023] ↩︎

  28. "The more expressive a language is, the greater the variety and quantity of ideas it can be used to represent" [@ExpressivePowerComputer2023] ↩︎

  29. "The term expressive power may be used with a range of meaning. It may mean a measure of the ideas expressible in that language: regardless of ease (theoretical expressivity); concisely and readily (practical expressivity)" [@ExpressivePowerComputer2023] ↩︎

  30. "The first sense dominates in areas of mathematics and logic that deal with the formal description of languages and their meaning, such as formal language theory, mathematical logic and process algebra" [@ExpressivePowerComputer2023] ↩︎

  31. "For example, the Web Ontology Language expression language profile (OWL2 EL) lacks ideas (such as negation) that can be expressed in OWL2 RL (rule language). OWL2 EL may therefore be said to have less expressive power than OWL2 RL. These restrictions allow for more efficient (polynomial time) reasoning in OWL2 EL than in OWL2 RL. So OWL2 EL trades some expressive power for more efficient reasoning (processing of the knowledge representation language)." [@ExpressivePowerComputer2023] ↩︎

  32. "G-code began as a limited language that lacked constructs such as loops, conditional operators, and programmer-declared variables with natural-word-including names (or the expressions in which to use them). It was unable to encode logic but was just a way to "connect the dots" where the programmer figured out many of the dots' locations longhand." [@Gcode2023] ↩︎

  33. "G-code (also RS-274) is the most widely used computer numerical control (CNC) and 3D printing programming language. It is used mainly in computer-aided manufacturing to control automated machine tools, as well as for 3D-printer slicer applications. The G stands for geometry. G-code has many variants." [@Gcode2023] ↩︎

  34. "The design of languages and formalisms involves a trade-off between expressive power and analyzability. The more a formalism can express, the harder it becomes to understand what instances of the formalism say. Decision problems become harder to answer or completely undecidable." [@ExpressivePowerComputer2023] ↩︎

  35. "[...] les langages algébriques, appelés aussi langages hors contexte, langages acontextuels, ou langages non contextuels. Ils sont reconnus par un automate à pile." [@HierarchieChomsky2023] ↩︎

  36. "Les langages [...] contextuels ou sensibles au contexte, sont exactement ceux reconnus par une machine de Turing non déterministe à mémoire linéairement bornée, appelés couramment automates linéairement bornés." [@HierarchieChomsky2023] ↩︎

  37. "La classe des langages contextuels (type 1) est incluse strictement dans la classe des langages récursivement énumérables (type 0). L'inclusion de la classe des langages algébriques (type 2) dans la classe des langages contextuels (type 1) doit être précisée car un langage contextuel ne contient jamais le mot vide ε. L'énoncé exact est : Un langage algébrique ne contenant pas le mot vide est un langage contextuel ou, de manière équivalente : Un langage algébrique est un langage contextuel éventuellement augmenté du mot vide." [@HierarchieChomsky2023] ↩︎

  38. "Le problème de l'appartenance d'un mot à un langage algébrique est décidable : il existe un algorithme qui, étant donnés la description d'une grammaire non contextuelle et un mot, répond en temps fini à la question de l'appartenance de ce mot au langage défini par cette grammaire (plus précisément, on peut le tester en un temps O(n^{3}) pour un mot de longueur n, grâce à l'algorithme CYK)." [@AutomatePile2021] ↩︎

  39. "Le problème de l'appartenance d'un mot à un langage de cette classe [la classe des langages récursivement énumérables] est indécidable." [@HierarchieChomsky2023] ↩︎

  40. "nondeterminism is when the execution of a program is not completely determined by its specification, i.e., at some point during the execution the specification allows the program to choose what to do next. During the execution, this choice is made by a part of the run-time system called the scheduler" [@royProgrammingParadigmsDummies, p.14] ↩︎

  41. "But paradigms that have the power to express observable nondeterminism can be used to model real-world situations and to program independent activities." [@royProgrammingParadigmsDummies, p.14] ↩︎

  42. "We conclude that observable nondeterminism should be supported only if its expressive power is needed." [@royProgrammingParadigmsDummies, p.14] ↩︎

  43. " - To help people learn is to help them build, in their heads, various kinds of computational models. - This can best be done by a teacher who has, in his head, a reasonable model of what is in the pupil's head." (Minsky, 1970, p.5) ↩︎

  44. "To the teacher of programming, even more, I say: identify the paradigms you use, as fully as you can, then teach them explicitly. They will serve your students when Fortran has replaced Latin and Sanskrit as the archetypal dead language." (Floyd, 1979, p.9) ↩︎

  45. "reading and working with more code, and more types of code, will increase proficiency at programming." (Brown, 2023, p.81) ↩︎

  46. "Experts build up a mental library of patterns" (Brown, 2023, p.81) ↩︎

  47. "One key difference between beginners and experts is that experts have seen it all before. Research into chess experts has shown that their primary advantage is their ability to remember and recognize the state of the board." (Brown, 2023, p.81) ↩︎

  48. "Concepts are not combined arbitrarily to form paradigms. They can be organized according to the creative extension principle." [@royProgrammingParadigmsDummies, p.16] ↩︎

  49. "If the need for pervasive modifications manifests itself, we can take this as a sign that there is a new concept waiting to be discovered. By adding this concept to the language we no longer need these pervasive modifications and we recover the simplicity of the program" [@royProgrammingParadigmsDummies, p.17] ↩︎

  50. "If we need to model several independent activities, then we will have to implement several execution stacks, a scheduler, and a mechanism for preempting execution from one activity to another. All this complexity is unnecessary if we add one concept to the language: concurrency." [@royProgrammingParadigmsDummies, p.17] ↩︎

  51. "If we need to model error detection and correction, in which any function can detect an error at any time and transfer control to an error correction routine, then we need to add error codes to all function outputs and conditionals to test all function calls for returned error codes. All this complexity is unnecessary if we add one concept to the language: exceptions." [@royProgrammingParadigmsDummies, p.17] ↩︎

  52. "After solving a challenging problem, ! solve it again from scratch, retracing only the insight of the earlier solution. I repeat this until the solution is as clear and direct as I can hope for. Then I look for a general rule for attacking similar problems, that would have led me to approach the given problem in the most efficient way the first time. Often, such a rule is of permanent value." [@floydParadigmsProgramming1979a, p.3] ↩︎

  53. "In computer science, one sees several such communities, each speaking its own language and using its own paradigms. In fact, programming languages typically encourage use of some paradigms and discourage others." [@floydParadigmsProgramming1979a, p.2] ↩︎

  54. "Furthermore, it is not at all clear how programming paradigms are to be characterised and differentiated. Indeed, on closer inspection, apparently disparate programming paradigms are very strongly connected. Rather, they should be viewed as different traditions of a unitary Computer Science paradigm composed of programming languages which are all Turing Complete, complemented by methodologies which may all be subsumed by Computational Thinking." [@michaelsonProgrammingParadigmsTuring2020, p.41] ↩︎

  55. "seeing a variety of programming paradigms will help further." (Brown, 2023, p.81) ↩︎

  56. "If the advancement of the general art of programming requires the continuing invention and elaboration of paradigms, advancement of the art of the individual programmer requires that he expand his repertory of paradigms." (Floyd, 1979, p.3) ↩︎