• Aucun résultat trouvé

[PDF] Documentation de formation approfondi sur LISP | Formation informatique

N/A
N/A
Protected

Academic year: 2021

Partager "[PDF] Documentation de formation approfondi sur LISP | Formation informatique"

Copied!
17
0
0

Texte intégral

(1)

Chapitre 1 : Lisp : les caractéristiques

Introduction

Ce dossier a pour objet de dégager les particularités du langage de programmation Lisp et l'intérêt qu'il présente pour des applications diverses ne relevant pas nécessairement de l'"intelligence

artificielle" (IA). Le Lisp est souvent associé univoquement, à tort, à l'IA; de fait, dans ce dossier, les références à cette branche de l'informatique sont anecdotiques.

On reconnaît à chaque langage une certaine spécificité. Le Fortran facilite le traitement numérique, ADA permet de développer d'importantes applications temps réel, le C est un langage machine de haut niveau convenant aux applications

proches du système opératoire. Le langage Lisp, quant à lui, porte l'abstraction à un très haut niveau, l'abstraction étant comprise comme la faculté de représenter simplement des problèmes complexes.

Le chapitre 1 est le chapitre principal. On y aborde la notion

d'abstraction dans le cadre d'un langage de programmation, et en quoi le modèle des données et de l'exécution du Lisp est spécifique. Y sont également abordés les prototypes évolutifs, la réutilisation, le domaine d'application du Lisp, et les particularités d'un

environnement de développement Lisp.

Le chapitre 2 passe en revue quelques-uns des préjugés les plus répandus à l'encontre du Lisp, comme celui de sa lenteur. Ce dernier étant lié à l'histoire du Lisp, le chapitre commence par un bref historique du Lisp.

Chacun des chapitres 3 à 5 présente un exemple illustrant un point ou l'autre du chapitre 1.

Le chapitre 6 propose un relevé non exhaustif des

produits Lisp disponibles sur le marché, par classe de matériel. Au chapitre 7, synthèse et conclusion de ce dossier.

On trouvera en annexe 1 une description du processus d'évaluation d'une expression Lisp et, en annexe 2, une brève description des applications Lisp développées par TRACTEBEL. L'annexe 3 porte sur la taille du Common Lisp et la portabilité des

applications Common Lisp.

Ce dossier est consacré au Lisp en général et au Common Lisp de façon plus spécifique (le Common Lisp est une des variantes

(2)

du Lisp ayant fait l'objet d'une définition standard - voir l'annexe 3). Certains aspects du Common Lisp ne sont pas ou peu abordés dans ce dossier et feront l'objet d'un document ultérieur. Il s'agit

principalement du système objet du Common Lisp (Common Lisp Object System ou CLOS) qui ajoute une autre dimension au pouvoir d'expression du Lisp, et des efforts de standardisation en matière d'outils de conception d'interface, comme CLIM (Common Lisp Interface Manager) et Common Graphics. Ces outils permettent de construire des interfaces hommes-machines indépendants du

système de fenêtrage de la machine hôte; de ce fait, ces interfaces graphiques sont portables d'un type de machine à l'autre.

Conventions d'écriture

Tous les mots appartenant à la définition du langage Lisp sont en italique, comme LIST dans :

(LIST 1 2 3) => (1 2 3)

D'autre part, cet exemple représente l'interaction que peut avoir un utilisateur avec un interpréteur Lisp, devant une console

d'ordinateur; si, à l'aide du clavier, l'utilisateur introduit

l'expression (LIST 1 2 3) , l'interpréteur Lisp répond en affichant à l'écran le résultat de l'évaluation de cette expression Lisp, soit la liste (1 2 3).

Ce dossier est aussi un ouvrage collectif. Je suis redevable à mes collègues qui ont bien voulu lire et commenter les versions

préliminaires de ce dossier, en particulier: C. VanDyck, N. Argani, M. Monteyne, P. Hendrickx, R. Paes, D.Paten et last but not least F. de Viron.

1.1. Langage et abstraction

En plus d'être un moyen de communication avec un ordinateur, un langage de programmation possède deux autres fonctions essentielles.

Premièrement, c'est un moyen de communication entre

programmeurs, les programmeurs passant une grande partie de leur temps à lire des programmes.

Deuxièmement, un langage de programmation sert de

(3)

tâches à accomplir par un ordinateur. Dans ce sens, il doit nous permettre de maîtriser la complexité des applications en nous aidant à construire des idées élaborées à partir d'idées plus simples. Pour ce faire,tout langage de

programmation recourt à trois mécanismes [ABEL85] :

des expressions primitives : par exemple des expressions

représentant des nombres (12, 3.2, ...) , des expressions représentant des opérateurs (fonctions) manipulant ces nombres (+, *, ...), des expressions représentant des chaînes de caractères, etc.

des moyens de combinaison : ils permettent de bâtir des

expressions composées à partir d'autres, plus simples. Par exemple : (+ 12 1) => 13 (* 5 (+ 1 2 3)) => 30 Remarque

"=> 13", signifie que l'interpréteur Lisp renvoie la valeur 13 quand il évalue

l'expression "(+ 12 1)". Pour plus de détails, voir en annexe 1 la description du processus d'évaluation d'une expression Lisp.

des moyens d'abstraction par lesquels des objets

composés peuvent être nommés et manipulés comme une unité. Ce mécanisme est tout à fait similaire à celui que nous (les humains) employons pour gérer la complexité du monde réel: comme le nombre de choses que nous pouvons traiter en même temps est limité, nous organisons l'information environnante en une succession d'abstractions dont le contenu sémantique est de plus en plus grand. Autrement dit, l'abstraction est la synthèse d'idées en de nouveaux concepts cohérents afin d'exprimer des idées plus complexes.

En ce qui concerne les langages de programmation, on distingue trois types d'abstractions : l'abstraction procédurale (ou algorithmique), l'abstraction des données et l'abstraction méta-linguistique.

(4)

Pour les développeurs, historiquement, l'abstraction procédurale est le premier outil de maîtrise de la complexité des logiciels. Les

procédures d'un programme seront organisées en plusieurs couches d'abstraction de plus en plus élevées; une couche supérieure est séparée de la couche immédiatement inférieure par une frontière d'abstraction, les détails d'implantation des procédures de la couche inférieure étant cachés aux procédures de la couche supérieure. Voici, en Lisp, un exemple simple d'abstraction procédurale :

(DEFUN SQUARE (X) (* X X) ) => SQUARE et ensuite, (SQUARE 2) => 4 où :

DEFUN est l'opérateur de définition d'une fonction

(DEFUN est l'acronyme de DEfine FUNction). Voir l'exemple 1 (chapitre 3) pour plus de détails sur DEFUN.

 SQUARE est le nom de la fonction,

 X est le paramètre formel de la procédure.

Contrairement à la plupart des langages de programmation, le Lisp ne limite pas arbitrairement l'abstraction procédurale. Le plus souvent, ces langages imposent les restrictions suivantes :

 les procédures ne peuvent être stockées dans des données

structurées comme les tableaux ou les enregistrements (record en anglais).

 la valeur que renvoie une procédure (une fonction) ne peut

être une procédure;

 une procédure doit être nommée et référencée par son nom.

L'abstraction des données

Concernant les données, un aspect important d'un langage réside dans les moyens dont il dispose pour construire des abstractions en combinant des données pour former des données composées.

Comme pour l'abstraction procédurale, le but est d'élever le niveau conceptuel auquel les programmes sont créés et d'augmenter la modularité de la conception (design). En particulier, l'abstraction des données est une technique générale qui permet de séparer d'une part, la partie d'un programme traitant du détail de la

(5)

représentation des données et d'autre part, la partie de ce

programme utilisant ces données; l'interface entre ces deux parties étant clairement définie, il est alors possible de modifier l'une des parties sans modifier l'autre.

L'abstraction méta-linguistique

Ces techniques d'abstraction rendent les programmes plus faciles à concevoir et à modifier. Toutefois, vient un moment où tout langage atteint ses limites dans la capacité qu'il a d'exprimer effectivement des idées complexes. Il est alors nécessaire d'établir de nouveaux langages pour mieux contrôler la complexité du domaine, comme on l'a fait quand on est passé du langage machine au Fortran. L'abstraction méta-linguistique, c'est-à-dire la construction de nouveaux langages descriptifs, joue un rôle important dans toutes les techniques de l'ingénieur en rapport avec la conception. En

informatique, un nouveau langage peut être implanté en terme d'un langage existant via un interpréteur (on parle alors d'embedded language ou de SPPL, special purpose programming language, le langage de base étant appelé implementation language).

Le Lisp est particulièrement adapté à ce type de technique grâce à ses capacités de traitement symbolique et à l'équivalence entre les programmes et les données (voir le paragraphe suivant). Il y a des exemples fameux de ce type d'approche : ainsi les

premiers langages de règle ont été implantés en Lisp; certains d'entre eux, comme KEEet ART, sont considérés comme les plus puissants à ce jour. Dans le domaine des outils de construction de systèmes-experts (outils écrits en Lisp), on peut encore citer G2: cet exemple est particulièrement intéressant, car c'est sans doute le seul outil générique (Lisp ou non) suffisamment élaboré et rapide pour faire des applications de contrôle de processus (temps

réel); G2 représente aussi un succès commercial évident: environ 34 millions de US$ de vente en 1992 (voir [ISS92/2]).

Cette technique d'abstraction est utilisée dans OPA-2, une application Lisp du Service Informatique de TRACTEBEL (voir l'annexe 2): KAL (Knowledge Acquisition Language) fait partie du module d'acquisition de la connaissance d'OPA; ce langage

spécifique permet à un ingénieur de représenter les étapes d'une procédure de conduite de centrale nucléaire.

Les exemples 1 à 3, chapitres 3 à 5, témoignent des possibilités d'abstraction du Lisp; de ce fait, on constate que l'essence

conceptuelle d'un programme Lisp apparaît clairement à un lecteur attentif. On observe aussi que la complexité intrinsèque de ce langage est minimum.

(6)

1.2. Modèle des données et modèle de l'exécution en

Lisp

Le Lisp est un langage fonctionnel (ou langage applicatif). Tout programme Lisp s'exprime en termes d'applications de fonctions à des objets (par objet, on entend ici une donnée en général, c'est-à-dire une donnée ou un programme). Une fonction prend zéro ou plusieurs objets comme arguments, effectue un traitement et renvoie un ou plusieurs objets comme résultats (un argument pouvant être lui-même une application de fonction).

En Lisp, toute donnée (ou valeur) est représentée par un objet ayant un type manifeste; le type d'un objet est dit manifeste s'il peut être testé et reconnu à l'exécution (le langage est typé dynamiquement). Contrairement aux langages où le type est statique (C, Fortran,...), il n'est pas nécessaire en Lisp de déclarer le type d'une variable. On peut déclarer le type d'une variable, limitant ainsi les valeurs de cette variable à une certaine gamme d'objets (pour des raisons d'optimisation par exemple, le

compilateur mettant à profit cette information pour générer un code machine plus efficace).

La gestion de la mémoire est automatique, le programmeur ne devant pas allouer explicitement la mémoire, ni faire utilisation du concept de bas niveau (langage machine) qu'est le pointeur (appelé aussi référence; voir l'exemple 3 du chapitre 5). La récupération et la réorganisation de la mémoire est assurée automatiquement par un système de ramasse-miettes (garbage collection), ce qui donne l'illusion d'une mémoire infinie. Ainsi une source importante de difficultés et d'erreurs est éliminée (par exemple, l'erreur de la référence folle). A noter qu'actuellement, le processus de ramasse-miettes est non-intrusif (il passe inaperçu aux yeux de l'utilisateur). Les fonctions Lisp sont elles-mêmes des objets du modèle des

données Lisp : de fait, elles sont représentées sous forme de listes, la liste étant une structure de donnée du Lisp. On dit qu'il y

a équivalence entre le programme et les données. Les

fonctions Lisp peuvent donc être traitées comme n'importe quelle valeur (par exemple être passées en argument d'un appel de fonction ou encore être stockées dans une structure de données). Ceci présente plusieurs avantages :

 De façon générale, cette propriété augmente le pouvoir

d'abstraction du langage (voir les exemples 1 et 2, chapitres 3 et 4).

 Certaines techniques de conception de programmes reposent sur la

non-différenciation des données et des programmes (par exemple la programmation dirigée par les données, voir [ABEL85]).

(7)

 Cette propriété est de première importance pour la création

des SPPLs (special purpose programming languages) car elle

simplifie notablement l'écriture des interpréteurs de ces langages. Il est facile d'écrire des programmes manipulant d'autres

programmes (voir l'exemple 2, chapitre 4).

 Cette similarité entre les données et les programmes permet

d'utiliser le Lisp comme un auto-macro-langage, c'est-à-dire un langage permettant de manipuler et d'étendre sa propre syntaxe (voir l'exemple 3, chapitre 5).

 Il est parfois intéressant de construire dynamiquement le nom

d'une fonction selon le contexte et de l'appliquer (si elle existe; voir l'exemple 3, chapitre 5).

Les fonctions Lisp peuvent être génériques, ce qui signifie qu'elles peuvent opérer sur différents types d'objets. En Lisp, ces fonctions font la différence durant l'exécution, mettant à profit le type manifeste de tout objet Lisp. Cela donne une flexibilité supplémentaire; par exemple, une fonction

composée à partir de fonctions génériques sera

automatiquement générique (voir l'exemple 1, chapitre 3).

1.3. Prototypage et développement évolutif

Grâce à son haut pouvoir d'abstraction, le Lisp facilite le développement évolutif.

En développement évolutif, une application est rapidement prototypée, ses différentes abstractions étant implantées le plus simplement et rapidement possible. Au besoin, comme c'est

souvent le cas, ces abstractions sont revues au fur et à mesure de l'évolution du projet et de la demande des utilisateurs. Lorsqu'une abstraction a démontré sa valeur, son implantation est améliorée en fonction de son importance et des compromis habituels

(performance, coût, etc).

Ce type d'approche ne doit pas être confondu avec l'approche du prototype à jeter. Celui-ci est conçu rapidement, sans soin particulier, pour être écarté dès qu'il a rempli son rôle (exemple : aider à clarifier ou formuler les besoins). Au contraire,

les prototypes évolutifs sont des programmes de qualité qui sont construits les uns à partir des autres et continuellement modifiés en fonction de l'avancement dans la connaissance du

domaine. Chaque prototype fait l'objet d'un cycle spécification-conception-implantation-test.

Si besoin est, d'un prototype évolutif, on peut faire un prototype opérationnel : il peut être intéressant de soumettre rapidement un prototype à l'utilisation et à la critique des futurs utilisateurs.

(8)

Il y a des expériences qui justifient ce type d'approche et des

rapports qui la recommandent. Ainsi, on peut lire dans un document du Defense Science Board Task Force on Military

Software (USA): We believe that users cannot accurately describe the operational requirements for a substantial software system without testing ... in an operational environment, and iteration on the specification; et encore : Experience with confidently specifying and paintfully building mammoths has shown it [incremental

implementation] to be the simplest, safest and even fastest to develop a complex software system by building a minimal version, putting it into actual use, and then adding function, enhancing speed, reducing size, etc (voir [GLAS91]).

Ou encore dans [BROO87] : "Therefore, one of the most promising of the current technological efforts, and one that attacks the

essence, not the accidents, of the software problem, is the development of approaches and tools for rapid prototyping of systems..."

Cependant, force est de reconnaître que le génie logiciel est sans doute la technique de l'ingénieur la moins mature, où, de plus, les pratiques habituelles sont très éloignées de celles reconnues comme étant les bonnes pratiques. Le développement évolutif est une

approche possible dans la description et la gestion du cycle de vie du processus de développement d'un logiciel; comme d'autres

approches, elle ne sera appropriée que dans certains contextes bien définis.

1.4. Réutilisation

En génie logiciel, la réutilisation est l'utilisation d'éléments logiciels existants pour la construction de nouveaux logiciels. La réutilisation est un moyen essentiel pour arriver à construire des logiciels fiables et rentables. L'abstraction est la dimension principale de la

réutilisation; autrement dit, abstraction and reusability are two sides of the same coin [WEGN83].

Le haut pouvoir d'abstraction du Lisp facilite la réutilisation de programme et l'extension de modules existants; le type manifeste de toutes données et les fonctions génériques permettent de définir des interfaces simples entre les modules, indépendants de détails d'implantation (voir l'exemple 1, chapitre 3, pour un cas simple de réutilisation).

(9)

Les applications informatiques deviennent de plus en plus complexes et ambitieuses; pour maîtriser cette complexité croissante, il est nécessaire de disposer de langages de

programmation adaptés, fournissant des moyens d'expression suffisants. Cependant, en pratique, les qualités d'un langage de programmation ne constituent qu'un élément du choix d'un langage pour un projet particulier.

Un langage de programmation sert au mieux un projet lorsque ses caractéristiques rencontrent au plus près les besoins du projet. Par son haut pouvoir d'expression, le Lispest particulièrement bien adapté aux applications possédant une ou plusieurs des

caractéristiques suivantes :

 les besoins fonctionnels sont initialement mal connus;

 les besoins évoluent constamment, même lorsque l'application est

déployée;

 le domaine est complexe ou très complexe.

Ceci ne signifie pas que le Lisp convienne à toute application possédant une ou plusieurs de ces caractéristiques: ainsi, de

nombreuses applications de base de données possèdent au moins la deuxième caractéristique; il ne viendrait pas à l'idée de développer ces applications en Lisp.

En ce qui concerne des applications moins ambitieuses, il existe diverses possibilités de développement et de déploiement

d'applications Lisp sur les micro-ordinateurs. On peut donc

envisager l'utilisation du Lisp pour de petites applications. Inutile cependant de considérer le Common Lisp si l'objectif est de fournir un exécutable compact: le seuil est de 2 à 4 MOctets selon

l'environnement utilisé (voir le paragraphe 2.2. et le chapitre 6). Le haut pouvoir d'abstraction du Lisp en fait un langage de choix dans les projets où l'équipe de développement est constituée

de développeurs plutôt que, plus traditionnellement, d'analystes et de programmeurs. Dans un projet informatique, un développeur participe aux phases de conception (design), d'implantation et d'évaluation de l'application; de préférence, il participe aussi à la phase de spécification et de faisabilité. Du fait du pouvoir

d'expression du Lisp, la phase d'implantation est réduite; du fait du partage vertical des phases du développement, la phase de

conception doit être moins détaillée. Le Lisp est donc susceptible d'intéresser tout ingénieur devant réaliser des développements informatiques.

1.6. Avantages de l'environnement de

développement Lisp

(10)

Les environnements de développement Lisp ont toujours représenté l'état de l'art en la matière. De nombreuses caractéristiques

d'environnement de développement trouvent leurs origines dans le monde Lisp, entre autres : les débogueurs symboliques, les

inspecteurs de données structurées, l'exécution pas à pas au niveau du code source et l'aide en ligne sur les opérateurs du langage. Programmer en Lisp offre de nombreux avantages directs entraînant une amélioration substantielle de la productivité; ainsi :

la compilation est incrémentale : le développement n'est pas

ralenti par le cycle habituel édition-compilation-lien-exécution (Fortran, C, etc.). Ainsi la redéfinition d'une fonction a un effet immédiat. Mieux, il est possible de modifier et d'ajouter du code en continu, y compris pendant l'exécution du programme (cela vaut aussi pour les structures de données, comme les classes et les objets de CLOS). Cette facilité est tellement appréciable, en terme de méthode de travail et de vitesse de développement, qu'aucun langage du futur ne pourra en faire l'impasse (langage lié dynamiquement). De fait, l'aspect dynamique et le pouvoir

d'abstraction élevé constituent deux des principaux plus du Lisp par rapport à des langages comme le C, le Fortran et le Pascal.

du fait de la nature dynamique du Lisp, l'environnement de

développement est très interactif: par exemple, il est possible de continuer l'exécution d'un programme après une erreur (après, par exemple, avoir spécifié la valeur à renvoyer par la fonction ayant provoqué l'erreur);

dans le Common Lisp, le mécanisme des packages (modules)

permet d'éviter le problème du conflit de noms (par exemple, nom identique pour 2 fonctions différentes); ce problème apparaît

fréquemment lorsqu'il est nécessaire d'utiliser plusieurs librairies ou lorsque le développement d'une application nécessite de faire appel à plusieurs programmeurs travaillant indépendamment.

le mécanisme de définition (defun) est paticulièrement flexible,

autorisant la définition d'arguments optionels (&optional) et par clefs (&key). Par exemple, en supposant les

arguments width et height de la fonction make-window définis à l'aide de clefs, toutes les applications suivantes sont valides: (make-window)

(make-window :width 120)

(make-window :height 100 :width 120)

Donc, dans le cas d'arguments définis à l'aide de clefs, on spécifie uniquement les arguments nécessaires et ce dans un ordre quelconque (les arguments non spécifiés ont une valeur par défaut). Ce mécanisme est très apprécié en phase de développement, des arguments pouvant être ajoutés à la

(11)

définition d'une fonction sans qu'il soit nécessaire de mettre à jour toutes les applications de cette fonction.

 les éditeurs offrent des fonctionnalités appréciables dans le

développement d'applications importantes et dans la maintenance des ces applications; par exemple :

o l'édition automatique d'une fonction (il suffit de cliquer sur

l'appel d'une fonction et d'activer la commande d'édition automatique pour ouvrir une fenêtre d'édition dans laquelle apparaît le code de la fonction appelée);

o une commande similaire permet de retrouver

automatiquement tous les appels (utilisations) d'une fonction dans l'ensemble de l'application;

o il est possible d'accéder simplement à la documentation de

toutes fonctions et de toutes variables globales, qu'elles soient primitives ou propres à l'application.

o la complétion automatique des noms de fonction et de

variables globales, qu'elles soient primitives ou propres à l'application (il suffit de taper les premiers caractères d'un nom de fonction; l'éditeur complète ou propose un choix de mots complétant les premiers caractères tapés).

Voir [LAYE91] pour une description complète de ce que peut offrir un environnement Lisp moderne.

Chapitre 2 : Lisp : les préjugés

2.1. Le Lisp est lent - Historique

Le Lisp a été inventé à la fin des années cinquante par John

McCarthy, comme un formalisme mathématique de raisonnement sur certains types d'expressions logiques. Lisp est l'acronyme de LISt Processing : dans ce formalisme, les programmes comme les données sont représentés sous la forme de listes. La

représentation analogue des programmes et des données est une caractéristique quasi unique parmi les langages de programmation; comme on l'a vu dans le chapitre précédent, cette caractéristique est de la plus haute importance.

Au début des années 60, McCarthy et ses collègues du MIT

Computation Center développèrent le premier interpréteur Lisp sur un IBM 704. Dans les années 60, le Lispservait principalement à des applications non numériques comme la dérivation symbolique, la linguistique et la démonstration de théorèmes; il était avant tout un langage de recherche, et l'aspect performance n'avait que peu

d'importance. A la suite de ses succès dans ces domaines

théoriques, les praticiens de l'informatique accordèrent au Lisp un intérêt grandissant. Alors seulement se posa la question des

(12)

compilateurs Lisp et de leur efficacité. Bien que ceci soit de l'histoire ancienne, la réputation d'inefficacité du Lisp a la vie dure.

Les implantations actuelles du Lisp sont basées sur des

compilateurs capables d'exploiter au mieux les caractéristiques de l'architecture du processeur hôte, tout comme les compilateurs de n'importe quel langage.

Voici le résultat de tests effectués sur une station Unix SUN3 (voir [GABR90]); le tableau ci-dessous donne les rapports

de Lisp au C pour le temps d'exécution et pour la taille du code généré par le compilateur, dans le cas de trois tests standard :

Rapports du Lisp au C (Lisp/C) pour:

le temps d'exécution la taille du code généré

Tak 0.9 1.21

Traverse 0.98 1.35

Lexer 1.07 1.48

Tak est un test mesurant l'efficacité de l'appel de fonctions (procédures) et des opérations sur les nombres

entiers. Traverse mesure l'efficacité de la construction et de l'accès à des structures (structures de données). Lexer concerne la

manipulation de caractères.

Dans le cas du Lisp, les tests ont été effectués sans tenir compte de la charge de la gestion automatique de la mémoire (par le ramasse-miettes, garbage collector en anglais); cela représente environ 2% du temps d'exécution (actuellement, ces ramasse-miettes sont non-intrusifs : ce processus passe inaperçu pour l'utilisateur).

Il existe d'autres comparaisons de ce genre, voir par exemple [FATE91] où il est montré que le Lisp se compare favorablement au C pour un test d'addition et de multiplication polynomiales. Concernant le calcul avec des nombres réels, les meilleurs compilateurs Lisp approchent les meilleurs

compilateurs Fortran (sans doute la référence en la matière). Voici le résultat d'un test de multiplication de matrices (100*100, single float) effectué sur une station Sun Sparc1+ (Allegro CL, Fortran Sun):

(13)

Lisp F77 F77 -fast C/Assembleur

0.73s 4.9s 0.48s 0.2s

A remarquer le facteur 10 entre le Fortran optimisé (F77 -fast) et le Fortran non optimisé (F77). Si un facteur 2 est réellement important, quelque soit le langage utilisé, il est sans doute préférable d'utiliser des librairies spécialisées (comme LAPACK, linear algebra package) qui donneront des résultats du genre de la dernière colonne du tableau (celle-ci correspond à un programme très optimisé où les 2 matrices initiales sont partagées en matrices de 2*3, la multiplication étant faite sur ces sous-matrices; ce

programme tient compte de l'architecture du processeur). Remarques

1. Etant donné l'augmentation rapide de la puissance des processeurs, il convient de minimiser l'importance de l'efficacité d'un compilateur en comparaison de la richesse de l'environnement de

développement et de la puissance du langage.

2. Outre le fait que le Lisp n'a rien à envier aux autres langages quant à ses performances, il dispose de caractéristiques intéressantes pour des applications purement numériques:

Nombres entiers

Contrairement au C et au Fortran, le Lisp permet une précision arbitraire sur les opérations en arithmétique des nombres entiers : il n'y a pas de limites quant à la grandeur d'un nombre entier; la mémoire est automatiquement allouée en fonction des besoins de la représentation.

Tableaux

Les tableaux sont dynamiques; le nombre de dimensions et la taille de chacune des dimensions ne doivent pas être fixés à la compilation (le nombre maximum de dimensions est d'au moins 7, selon le standard Common Lisp).

Un tableau peut être ajustable : une fois créé, la taille de chacune de ses dimensions peut être augmentée (par

exemple, ceci se révèle très utile dans certaines applications de la théorie des graphes).

Un tableau peut être défini comme le sous-tableau physique d'un autre; cela se fait simplement, en une étape, à la

(14)

Types et fonctions arithmétiques prédéfinis Le Common Lisp possède un grand nombre de types prédéfinis (integer, rational, complex rational, complex integer, short float, single float, double float, long float,

complex, ...). De plus y sont disponibles nombre de fonctions arithmétiques (élémentaires, trigonométriques,

hyperboliques, logiques, etc.).

2.2. La gestion automatique de la mémoire pose

problème en pratique

Les langages qui possèdent une gestion automatique de la mémoire (voir le paragraphe 1.2.) font appel à un système de

ramasse-miettes (garbage collector). Au début de l'introduction de cette technologie, un ramasse-miette pouvait effectivement introduire des pauses assez longues au cours du déroulement d'un

programme. Aujourd'hui, cette technologie a évoluée, les ramasses-miettes sont devenus non intrusifs: tout se passe comme si la

gestion de la mémoire a lieu en tâche de fond, de façon

imperceptible. Cette évolution autorise l'utilisation de langages comme le Common Lisp et Smalltalk pour des applications temps réel (pour un exemple, voir l'application - TRACTEBEL - GPS).

2.3. Une application Lisp nécessite beaucoup de

mémoire centrale

Cette affirmation est partiellement vraie. En Lisp toutes les

fonctions primitives du langage sont directement chargées, même si l'application n'utilise qu'une partie des primitives; de plus

le Common Lisp est un langage volumineux comportant un grand nombre de primitives (voir l'annexe 3 concernant la taille

du Common Lisp). Du fait de la nature dynamique du Lisp, il n'est généralement pas possible de déterminer statiquement l'ensemble des fonctions primitives qui seront utilisées par une application. Au contraire, dans les langages conventionnels, une application est liée sélectivement aux librairies de sous-programmes utiles (processus de lien ou link).

Depuis quelques années, diverses techniques sont utilisées pour réduire la taille de l'image Lisp. La plus simple est le chargement sélectif automatique : une fonction réside dans un fichier sur

disque, jusqu'au moment de la première utilisation où elle est alors chargée en mémoire. Grâce à ces techniques, des

applications Lisp complexes tournent avec 3 mégabytes de mémoire centrale (pour un exemple sur un Macintosh, voir [BARB91]; en développement, il faut disposer d'un minimum de 4 Mb). (*)

(15)

Actuellement, dans le monde de l'informatique professionnelle, la configuration du PC compatible la plus vendue comprend un

processeur 80386 ou 80486 et 4 mégabytes de mémoire centrale, cela afin de permettre de tourner MS Windows dans de bonnes conditions. De nombreuses stations Unix de bas de gamme, quant à elles, sont livrées systématiquement avec 16 Mb. Ceci est bien sûr lié à la diminution vertigineuse du coût de la mémoire centrale. L'impact des besoins en mémoire sur le coût total d'une application est devenu négligeable. En outre, on observe une adéquation entre la disponibilité en mémoire centrale des micro-ordinateurs actuels, et les besoins en mémoire d'une application Lisp.

——————————————————

(*) A noter que l'évolution générale (tous les langages) va vers une augmentation des besoins en mémoire.

2.4. La syntaxe du Lisp est compliquée ("et toutes

ces parenthèses!")

La syntaxe du Lisp est extrêmement simple (*) et il y a très peu de manières différentes de construire des expressions composées. D'où, malgré une fréquente répulsion initiale pour la notation polonaise (ou notation préfixée), un apprentissage aisé et naturellement progressif, en fonction des besoins. Une

expression Lisp syntaxiquement correcte s'écrit sous la forme d'une liste représentant l'application d'une fonction (ou opérateur) à des arguments (voir l'annexe 1 pour plus de détails) :

(<fonction> <argument1> <argument2> ...) Exemples : (+ 1 2) => 3 (* 3 2) => 6 (+ 1 2 3 (* 3 2)) => 12 (LIST 1 2 3 4) => (1 2 3 4) (FIRST (LIST 1 2 3 4)) => 1

(16)

C'est à peu près tout ce qu'il y a à retenir de la syntaxe du Lisp. L'essentiel de la ponctuation Lisp consiste en les parenthèses gauche et droite. De fait, le tour complet des propriétés formelles du langage se fait en une heure, comme pour les règles du jeu d'échecs. Pour l'apprenti programmeur Lisp, les détails syntaxiques du langage passent très rapidement à l'arrière-plan.

La lecture de listes imbriquées dans de nombreuses parenthèses est simplifiée par quelques règles d'indentation appropriées (comme l'alignement vertical des objets d'un même niveau logique); par exemple : (+ 120 (* 2 3 4) (* 55 (+ 12 56) (* 23 44)) (+ 5 23))

Les éditeurs Lisp indentent automatiquement les expressions Lisp, comptent les parenthèses et détectent les parenthèses manquantes ou en excès. Si le curseur est positionné juste derrière une

parenthèse droite, l'éditeur met en évidence la parenthèse gauche correspondante (par exemple en la faisant clignoter). De plus, un éditeur Lisp fournit de nombreuses commandes de déplacement à travers ces listes, comme la commande de déplacement du début à la fin d'une liste et la commande inverse.

A remarquer aussi, l'avantage de la notation préfixée par rapport à la notation habituelle infixée : l'opérateur + peut prendre plus de deux arguments. D'autre part, du fait que chaque application d'un opérateur est entre parenthèses, il n'est pas besoin de règles compliquées de priorité des opérateurs; ainsi, en Fortran, que vaut 2*7-5+2 (2multiplie-t-il 7-5+2 ou seulement 7, etc.)? ————————

(*) Il suffit de comparer les délimiteurs syntaxiques existant en Lisp et dans d'autres langages pour comprendre un des aspects de la simplicité de la syntaxe du Lisp :

Lisp ( )

C , . ( ) ; [ ] { } -> Cette simplicité est une des raisons expliquant le succès du Lisp comme langage d'extension dans des progiciels

comme AutoCAD (CAO), Interleaf (PAO) et EMACS(éditeur) : il est très facile de construire un analyseur syntaxique du Lisp.

(17)

2.5. Le Lisp est difficile et est réservé à

l'"intelligence artificielle"

Par rapport à d'autres langages, le Lisp est plutôt facile à apprendre : d'une part, la syntaxe est simplissime et d'autre part

le Lisp possède une série de caractéristiques qui simplifient l'écriture des programmes, comme la gestion automatique de la mémoire (il n'est pas nécessaire de manipuler des pointeurs, ni d'allouer et de libérer explicitement de la mémoire). Ce qui est vrai par contre, c'est que le Lisp permet des techniques de

programmation particulières, généralement non utilisables dans d'autres langages; l'apprentissage de ces techniques nécessite un effort supplémentaire, mais il a pour corollaire une plus grande aisance dans la maîtrise de la complexité des applications.

Une façon de se convaincre des idées exposées dans le paragraphe précédent est de consulter la référence [ABEL85], Structure and Interpretation of Computer Programs, un livre qui est un des cours de base des étudiants du MIT :

premièrement, le langage utilisé pour ce cours de méthodes de programmation est le Lisp; si ce langage était difficile, il n'aurait pas été utilisé pour un cours de débutant (et ne pensez pas que les étudiants du MIT soient plus intelligents que ceux d'une université européenne)! De plus, à aucun moment dans ce livre, il n'y a de description exhaustive du langage. L'importance du langage de programmation, le Lisp en l'occurence, y apparaît comme

secondaire par rapport aux méthodes de programmation exposées (c'est bien ainsi que cela doit être);

deuxièmement, en comparant la table des matières de ce livre avec celle d'un cours traditionnel d'introduction à l'informatique (basé sur le Pascal, le C ou le Fortran), on voit de suite que le nombre de concepts de programmation exposés est nettement plus important dans ce livre : on y trouve l'approche objet, la progammation

logique, l'écriture d'interpréteurs, etc. L'exposé de ces concepts est théorique et pratique : on y écrit effectivement en Lisp un

interpréteur ou on simule effectivement en Lisp un langage à objets... Ceci est à mettre à l'actif du Lisp et non à la qualité des auteurs du livre (qui est inconstestable, il est vrai)!

Finalement ce livre démontre aussi que le Lisp n'est pas qu'un langage réservé à l'"intelligence artificielle" et qu'en particulier, il convient très bien à l'apprentissage et la mise en oeuvre de méthodes de programmation sophistiquées.

Références

Documents relatifs

Nous voulons dans ce mémoire comparer le test de Box et Pierce et celui de Hong à une nouvelle statistique de test reposant sur une comparaison entre un estimateur de la

Mais en réalité, ce discours galant qui feint de regretter sans cesse de ne pouvoir occuper le premier rang peut à bien des égards être considéré aussi comme un leurre : la

Rhétorique du discours pamphlétaire à travers l’Ajaccio vendicata dall’accusa di cospirazione contro l’impero francese d’Alexandre Colonna d’Istria (1809)

multiplier test statistic for causality in variance between two univariate time series using multivariate GARCH models is studied in Hafner and Herwartz (2006) and these authors

Les découvertes de la Tène sur le plateau du Braden se situent dans un c ontexte chronologique plus vaste mais représen~ nt l'aspect essentiel des. gisements

Bâtiments quadrangulaires du type Blockbau et peut-être Schwellenbau, établis à l'origine sur fond excavé puis sur

The objective of this paper is to offer an insight as to why many previous studies are not directly applicable when considering class imbalance, data heterogeneity and data vo- lume

Les seules structures directement datables sont des fosses, dont le comble- men t détritique contient de la céramique attribuable d'une part au Hallstatt final,