URL: https://linuxfr.org/users/montaigne/journaux/lexpressivit%C3%A9-des-langages Title: L'expressivité des langages Authors: Ontologia Date: 2007年05月30日T18:02:10+02:00 Tags: Score: 0 Le contenu de LinuxFr parlant encore une fois peu de son sujet principal, je vais me dévouer une nouvelle fois afin de tenter de lancer un débat intéressant (?), sur le même sujet qui me tiens toujours à coeur ;-) Golum va nous manquer, mais on fera sans :( C'est une lapalissade de dire que l'on cherche à créer des langages permettant de disposer de plus d'expressivité afin d'améliorer la productivité. Des langages comme Ruby, caml, perl, python, etc... sont à la mode, permettent d'aller plus loin, de diminuer la taille du code, en sacrifiant parfois à la lisibilité. Il me semble depuis quelques mois que mes réflexion avancent sur ce sujet, que la clé d'une (r)évolution réelle des langages de programmation nécessite la mise au point d'un langage déclaratifs (axiomatiques) turing complet. Les expression régulières, le langage Xpath, le Sql, etc... sont des langages axiomatiques, déclaratifs sans être turing complet, et c'est bien normal car leur objectif est d'être spécialisé, ce qui permet leur existence. En effet, passer du paradigme régnant aujourd'hui en maître dans les paradigmes de langages - consistant à décrire à l'ordinateur les étapes successives de traitement permettant d'aboutir à un résultat - à des paradigmes dans lequel on décrit quelques règles de manières déclaratives en demandant à la machine d'inférer, est une étape difficile, peu explorée en réalité, et posant plein de problèmes théoriques. Adoptons une démarche incrémentale. Les langages actuels, langages fonctionnels y compris, se contentent de décrire un graphe orienté, décrivant le parcourt d'un automate virtuel. Que l'on ajoute tous le sucre syntaxique que l'on veut, que l'on permette de mettre des fonctions en paramètres d'autres fonctions, on est toujours rappelé par cette réalité. L'objectif des librairies, de la programmation fonctionnelle, objet, est souvent de cacher localement cette réalité, en rendant déclaratif certains traitements. Certains langages, parce que dynamiques ou bien compilé, sont grâce à leur sémantique interne capables d'implémenter des traitement déclaratif de haut niveau. Les langages fonctionnels, ou objets implantant une sorte de type _Block_ (ie. correspondant à une liste d'instructions) permettent en effet de définir des fonctions exécutant un code donné en argument dans certains cas, de procéder à des opérations ensemblistes sur des tableaux avec des fonctions de comparaisons données par les utilisateurs. En particulier, on peut y implémenter les opérations de bases chères au utilisateurs de langages fonctionnels, comme map, fold et filter : [http://www.cse.unsw.edu.au/~en1000/haskell/hof.html](http://www.cse.unsw.edu.au/~en1000/haskell/hof.html) **[1]** Ces fonctions restent assez abordables et sont d'une puissance fabuleuse. Je rappel une problématique qui me semble clé : Un langage plus expressif, plus puissant, doit l'être tout en restant le plus abordable possible, avec l'approche qui a prévalu lors de la création d'un langage comme LOGO ou AppleScript : permettre à des non informaticiens un minimum logique d'écrire au moins de petits programmes. Si on oublie cette problématique, alors la question est réglée : il faut jeter Java/C#/C++, et former tout le monde d'urgence à Haskell/Caml/Lisp/Oz. Malheureusement, peu de développeurs ont le niveau théorique leur permettant de maîtriser un tel langage. Je me souviens que la plupart de mes collègues de BTS ne maîtrisaient pas vraiment le concept de fonction d'un point de vue théorique (produit cartésien, tout ça), mes collègues de boulot pareil (la fameuse réponse "un langage fonctionnel ? C'est un langage qui marche ?"). Et même des gens très qualifiés peu habitué à cette logique ne la trouve pas aisée à prime abord. Un exemple récent est cet échange [http://linuxfr.org/comments/834613.html#834613](http://linuxfr.org/comments/834613.html#834613) **[2]** dont tout habitué de LinuxFR reconnaîtra des interlocuteurs très compétents. Bref, je pense que la formation n'est pas l'unique problème de la marginalité des langages fonctionnels, même si elle reste importante. Plusieurs voies d'évolution: **_Le déclaratif sur les données_** La plupart du temps, les données sur lesquels on travaille ont une forme d'arbre, on est donc en terrain connu, et des formalismes comme Object Query language (ou tout autre query language conçu pour Xml) par exemple, permettent de rendre déclaratives des opérations qui en ont bien besoin. En effet, d'après [http://www.st.cs.uni-sb.de/edu/seminare/2005/advanced-fp/doc(...)](http://www.st.cs.uni-sb.de/edu/seminare/2005/advanced-fp/docs/sweeny.pdf) **[3]** , 90 % des entiers du code source du jeu Unreal sont dédiés à parcourir des tableaux. C'est certes un exemple spécifique de par la part prépondérante de concepts issus d'algèbre linéaire dans ce genre de logiciel, mais pour des logiciels de gestion, on en est sûrement pas très loin, en tout cas en ce qui me concerne. Disposer d'un SQL objet built in le langage permet d'accéder beaucoup plus vite à l'_intuition_ du développeur, gage de réduction d'erreurs, de productivité, comme l'expliquait Victoria Livschitz dans une interview (traduction française aproximative ici : [http://linuxfr.org/~Montaigne/19629.html](http://linuxfr.org/~Montaigne/19629.html) **[4]** ). En effet, on se retrouve ici avec un problème de (sucre) syntaxe(ique) : même si l'on peut implémenter des fonctions sur listes permettant de réaliser des intersections, unions, différence avec en argument la fonction de comparaison, permettant au fin du fin de recomposer à peu près proprement et à peu près déclarativement une requête SQL, ces dernières sont plus intuitives car tout simplement plus proches du langage naturel. Par exemple pour trouver les chaîne égales, dans listStr au chaînes embarquées dans un objet Item : Select listStr.element from listStr, listItem where listStr.element = listItem.element.link (ici élement est le nom que l'on donne au champ d'une table avec un champ unique, un tableau de chaîne par exemple) On peut l'écrire aussi : liststr.intersection(listItem, {listStr.element = listItem.element.link}); ou pire en java Vector t3 = listStr.intersect_with_func(listItem,new FonctionBool() { £spaces£ £/spaces£public boolean compare(Object el1, Object el2){ return ((String)((Item)el1).link).equals((String)el2)); } } £spaces£ £/spaces£); **_La richesse dans la déclaration des structures_** D'après **[3]**, page 35 une statistique impressionnante : 40 % des for du code du moteur d'Unreal sont des compréhensions fonctionnelles, c'est à dire une liste du genre : s = [ x | x E [0..inf] | x2>36 ]; s est bien entendu une liste. Il faut bien reconnaître que les variables déclarées classiquement dans nos langages typés (Java/C# pour citer les plus utilisés dans l'industrie) sont des stéréotypes directement issus de la machine. Un entier est arbitrairement compris entre -2^n et 2^n Une chaîne est une liste de caractère. Un flottant est de même un nombre compris entre -2^n et 2^n mais avec des décimales en +, elle même cadrées. Bref, ce n'est pas intuitif, et le programmeur est obligé de tracer les effets de bords et les répercutions de ce genre de partis pris aux racines historiques. Il serait peut être temps de proposer des langages à vocation industrielle, d'informatique de gestion, ayant des syntaxes permettant de décrire une variable selon une structure prédéfinie, et non plus un stéréotype machine calqué sur les registres du processeur. Que ce modèle fut valable sur des machines tournant à quelques mégahertz et quelques centaines de Ko de mémoire est parfaitement cohérent. Mais avec presque 3 Ghz et plusieurs Go, des compilateurs puissant permettant une analyse de flot (analyse de toutes les exécutions possible du code, ce genre d'algo consomme beaucoup de mémoire à la compilation), il serait peut être temps... Après cette digression, quelques exemple : Une chaîne avec un masque str : \d{2}-\d{3}-\d{2} ou le contenant str : [ String | contains \d{2}-\d{3}-\d{2} | StartWith W]; Un entier appartenant à un sous ensemble de |N i : [ x : Int | x E [0..inf] | x mod 2 = 0 | x>51]; **_Un pattern matching à tout les étages_** L'idée d'utiliser du filtrage à haut niveau se retrouve dans Caml, ou plus récemment dans TOM [http://tom.loria.fr/](http://tom.loria.fr/) **[5]** En caml, on peut faire du filtrage de type, ainsi que de forme de liste. A ma connaissance, on ne peut pas faire grand chose de plus, mais c'est déjà assez puissant. TOM, dont je reprendrai ici juste des idées, permet déjà de faire des choses un peu plus sioux (je reprend ici un slide [http://sedre.loria.fr/seminaire/060203-ACL-YTo.pdf](http://sedre.loria.fr/seminaire/060203-ACL-YTo.pdf) **[6]**) (x*,a,y*) : recherche l'élément a dans la liste f(X1*,x,x,Y*) -> f(X*,x,Y*) : élimine des doublons. Ca ressemble encore beaucoup à du langage mathématique, mais c'est pas mal intuitif TOM est très intéressant, mais comme tous les trucs de la fac, ça y restera, et de toutes façons c'est quasiment imbitable. Ce serait un langage très intéressant à recomposer afin d'en faire quelque chose d'un minimum intuitif. On pourra aussi proposer de la manipulation d'arbre : [ £spaces£ £/spaces£<b @Match "(i.*)"=@Match"\d+">[ £spaces£ £/spaces£@Match ".*?\d+.*?Attention.*" £spaces£ £/spaces£] £spaces£ £/spaces£@Match "(.*)" £spaces£ £/spaces£] £spaces£ £/spaces£-> [ £spaces£ £/spaces£[ £spaces£ £/spaces£<bla id="3" @Match.capt 1=@Match.capt 2>@Match.capt 3 £spaces£ £/spaces£] £spaces£ £/spaces£] ou [ £spaces£ £/spaces£@match_grammar "(.*?)ELEMENT `(?[0-9]+[A-Z]?)?`{'and',',',' ',`(?[0-9]+[A-Z]?)?`}(.*?)" £spaces£ £/spaces£] £spaces£ £/spaces£-> [ £spaces£ £/spaces£@capt 1 @match_grammar.captur.foreach elt <ref id=@fonctionTrouveIDde(elt)>[(elt)] £spaces£ £/spaces£]; ( les `` servent à capturer Bon ma syntaxe est pourrie (et pas intuitive ;-), mais l'idée est décrire des sortes de regexp, et de définir des règles de transformation Le dernier exemple est un cas réel dans sa forme (complètement réécris bien sûr), et m'a posé pas mal de problèmes, à coder à la main, en java. Le problème du pattern-matching, lorsqu'on le mélange à un paradigme classique de description d'automate virtuel, est le bordel que ça implique dans le code car cela peut rentrer en collision avec des données (la variable tmp de type string qui peut valoir toutes sorte de choses le long de l'exécution du programme). Je ne parle même pas de la programmation orientée Aspect, cette intéressante bidouille, qui consiste à faire faire à l'automate des sauts en 4ème dimension du graphe... **_Vers une grammaire à langage naturelle_** Car là est peut être la clé la plus fondamentale du changement: un langage intuitif est proche du langage naturel (non, Cobol est un faux contre exemple). Mais cela nécessite peut être de dépasser les grammaires LL, LR, etc... Ces grammaires vérifient une liste de règle basé sur le typage d'expression. Une grammaire de langage naturelle, se base sur la nature des mots, et de celle-ci émerge une fonction. C'est le sens du mot combiné avec le graphe syntaxique qui fait émerger le sens. Le gros problème de ces grammaires est leur potentielle ambiguïté. J'ai rien d'autre d'intelligent à dire sur ce sujet ;-)

AltStyle によって変換されたページ (->オリジナル) /