Le langage LISP

LISP

À la fin des années 1950, les ordinateurs savent déjà effectuer rapidement des calculs numériques. Avec FORTRAN, les scientifiques disposent même d’un langage de haut niveau efficace pour exprimer leurs formules. Mais les chercheurs qui commencent à travailler sur l’intelligence artificielle rencontrent un autre problème : ils veulent manipuler des symboles, des règles logiques, des expressions algébriques, des phrases et des structures dont la taille n’est pas connue à l’avance.
C’est dans ce contexte que John McCarthy imagine Lisp. L’idée naît pendant les travaux qui suivent la rencontre de Dartmouth de 1956, l’un des moments fondateurs de l’histoire de l’intelligence artificielle, et prend forme au MIT à partir de 1958. Le langage repose sur un choix qui paraît étrange au premier regard : représenter les informations sous forme de listes imbriquées. Ce choix va pourtant permettre quelque chose de beaucoup plus profond.
En Lisp, un programme peut être représenté avec les mêmes structures que les données qu’il manipule.Les parenthèses sont devenues son signe distinctif, parfois jusqu’à la caricature. Elles ne sont pourtant que la partie visible d’un langage qui a contribué à diffuser la récursion, le calcul symbolique, la gestion automatique de la mémoire, la programmation interactive et la transformation des programmes par les programmes eux-mêmes. Pendant plusieurs décennies, Lisp sera l’un des principaux langages de la recherche en intelligence artificielle.

Date d’apparition : 1958

  • 1956 : pendant le Dartmouth Summer Research Project on Artificial Intelligence, John McCarthy réfléchit à un langage algébrique adapté au traitement de listes.
  • 1958 : arrivé au MIT, McCarthy lance avec son équipe l’implémentation de Lisp sur l’IBM 704.
  • 1960 : il publie Recursive Functions of Symbolic Expressions and Their Computation by Machine, l’article fondateur du langage.
  • 1962 : le LISP 1.5 Programmer’s Manual donne une définition pratique du système et contribue à sa diffusion.
  • Années 1960-1970 : plusieurs branches apparaissent, notamment Maclisp au MIT et Interlisp chez BBN puis Xerox PARC.
  • 1974 : Richard Greenblatt décrit au MIT le projet d’une machine spécialement conçue pour exécuter Lisp.
  • 1975 : Gerald Jay Sussman et Guy Steele présentent Scheme, un dialecte plus petit fondé sur une lecture renouvelée du calcul lambda.
  • 1981-1984 : plusieurs communautés rapprochent leurs dialectes pour former Common Lisp, qui devient rapidement un standard de fait.
  • 1994 : Common Lisp devient un standard ANSI.
  • 2007 : Clojure montre que la famille Lisp peut encore être réinterprétée pour la JVM, la programmation fonctionnelle et la concurrence.

Donner une seule date de naissance reste donc un raccourci. Les idées commencent à se former en 1956, l’implémentation démarre en 1958 et la première publication scientifique paraît en 1960. Pour une fiche chronologique, 1958 reste la date la plus naturelle.

 

À quel besoin répond Lisp ?

Lors de la conférence de Dartmouth, McCarthy découvre notamment IPL, le langage utilisé par Allen Newell, Cliff Shaw et Herbert Simon pour leurs travaux sur Logic Theorist. IPL sait manipuler des listes, mais sa syntaxe reste très liée à la machine sur laquelle il fonctionne. McCarthy cherche une écriture plus proche des mathématiques et plus facile à composer.

Son propre projet d’intelligence artificielle, l’Advice Taker, renforce ce besoin. Pour faire raisonner un ordinateur, il faut représenter des phrases, des relations et des expressions logiques, puis les démonter, les comparer et en construire de nouvelles. Une simple suite de nombres convient mal à ce travail. Les listes imbriquées, en revanche, représentent naturellement des arbres et des expressions symboliques.

Lisp naît donc moins du besoin de calculer plus vite que de la nécessité de représenter et transformer des structures symboliques.

Pourquoi des listes ?

Une liste peut contenir des éléments simples, appelés historiquement des atomes, mais aussi d’autres listes. Elle permet ainsi de représenter une structure de profondeur quelconque :

(A (B C) (D (E F)))

Cette écriture peut être vue comme un arbre. Une branche peut elle-même contenir plusieurs branches, sans qu’il soit nécessaire de connaître à l’avance la taille de l’ensemble. Pour les chercheurs qui manipulent des formules, des démonstrations ou des phrases, cette souplesse est précieuse.

Le terme LISP vient de LISt Processor. Aujourd’hui, on écrit généralement Lisp lorsqu’on parle de la famille de langages, même si les documents historiques utilisent souvent les majuscules.

Pourquoi toutes ces parenthèses ?

Lisp utilise une notation préfixée : l’opération apparaît avant ses arguments. Une addition s’écrit par exemple :

(+ 2 3)

et l’expression mathématique (2 + 3) × 4 devient :

(* (+ 2 3) 4)

La première parenthèse ouvre une expression, le premier élément indique l’opération et les suivants sont ses arguments. Il n’est donc plus nécessaire de définir une priorité particulière entre +, * ou d’autres opérateurs : la structure de l’expression est visible directement.

John McCarthy avait pourtant imaginé une autre écriture, les M-expressions, plus proche de FORTRAN. Les listes parenthésées, appelées S-expressions, devaient surtout servir de représentation interne. L’arrivée de l’interpréteur rend les S-expressions directement utilisables pour programmer, et les M-expressions finissent par disparaître du projet. Les parenthèses qui devaient rester cachées deviennent ainsi l’une des syntaxes les plus reconnaissables de l’histoire de l’informatique.

CAR, CDR et CONS : des noms venus de l’IBM 704

Les premiers Lisp sont développés sur l’IBM 704, une machine à mots de 36 bits. Deux champs de 15 bits de certains mots sont directement accessibles par des instructions de la machine : la partie address et la partie decrement. Les premières cellules de liste utilisent précisément ces deux champs pour mémoriser deux adresses.

Cette organisation laisse trois noms célèbres dans le langage :

(car '(A B C))       ; donne A
(cdr '(A B C))       ; donne (B C)
(cons 'A '(B C))     ; construit (A B C)

CAR vient historiquement de Contents of the Address part of Register, CDR de Contents of the Decrement part of Register, tandis que CONS signifie simplement construct. Le matériel qui a accueilli le premier Lisp a donc laissé son vocabulaire dans des dialectes encore utilisés plusieurs décennies plus tard.

La récursion au cœur du langage

Durant l’été 1958, McCarthy travaille notamment sur la différentiation symbolique. Une expression mathématique possède naturellement une structure récursive : une somme contient des termes, qui peuvent eux-mêmes être des produits ou d’autres expressions. Il devient logique de définir une fonction capable de s’appeler elle-même pour descendre dans cette structure.

Un exemple moderne en Common Lisp montre bien le principe :

(defun somme (liste)
  (if (null liste)
      0
      (+ (car liste)
         (somme (cdr liste)))))

La fonction prend le premier élément avec car, puis recommence sur le reste de la liste avec cdr. Lorsqu’il ne reste plus rien, elle renvoie zéro.

McCarthy emprunte aussi la notation lambda aux travaux d’Alonzo Church. Une fonction peut alors être créée et manipulée comme une valeur. Cette association entre fonctions, récursion et structures de listes donne à Lisp un modèle de programmation très différent des langages impératifs dominants de l’époque.

Quand le programme devient une donnée

La caractéristique la plus originale de Lisp apparaît lorsque l’on compare ces deux expressions :

(+ 2 3)

'(+ 2 3)

La première demande l’addition et produit 5. L’apostrophe devant la seconde empêche son évaluation immédiate : Lisp considère alors (+ 2 3) comme une simple liste contenant trois éléments.

On peut donc construire, inspecter ou modifier cette liste comme n’importe quelle autre donnée, puis éventuellement demander son exécution :

(setq expression '(+ 2 3))
(eval expression)

eval renvoie ici 5. Cette proximité entre la représentation du programme et celle des données est souvent décrite par le terme homoiconicité. Elle permet notamment aux macros Lisp de recevoir du code sous forme de structure, de le transformer puis de produire un nouveau programme.

L’histoire réserve ici un épisode remarquable. McCarthy avait écrit eval comme une définition théorique destinée à son article. Steve Russell remarque que cette définition peut servir directement d’interpréteur, la traduit à la main en code machine et donne ainsi au système un interpréteur Lisp opérationnel. Une construction pensée pour expliquer le langage devient l’un de ses mécanismes pratiques.

La mémoire se libère toute seule

Les programmes Lisp construisent continuellement de nouvelles listes. Très vite, une question se pose : que faire des cellules qui ne sont plus accessibles ? Demander au programmeur de les libérer manuellement compliquerait fortement les fonctions récursives que McCarthy cherche justement à rendre simples.

Les premiers systèmes Lisp adoptent donc une récupération automatique de la mémoire. Lorsque la réserve de cellules libres s’épuise, le système repère les structures encore accessibles depuis le programme et récupère les autres. Le principe correspond à ce que l’on appellera couramment un garbage collector.

Cette gestion automatique a un coût sur les machines de l’époque, mais elle libère le programmeur d’une partie importante de l’administration de la mémoire. Bien avant Java, C# ou JavaScript, Lisp fait ainsi de la récupération automatique des objets inutilisés une composante normale de l’environnement d’exécution.

Un langage fait pour travailler de manière interactive

L’interpréteur change aussi la manière de programmer. Une fonction peut être saisie, exécutée, modifiée puis redéfinie sans reconstruire tout le programme. Cette méthode s’accorde particulièrement bien avec le temps partagé qui se développe au MIT durant les années 1960.

Le cycle de travail devient très direct : lire une expression, l’évaluer, afficher le résultat, recommencer. C’est le principe du REPL, pour Read-Eval-Print Loop, aujourd’hui familier dans de nombreux langages interactifs.

Lisp ne reste pas pour autant un langage seulement interprété. Timothy Hart et Michael Levin réalisent l’un des premiers compilateurs Lisp efficaces, lui-même écrit en Lisp. Les environnements ultérieurs combinent naturellement interprétation, compilation, débogage et modification interactive du programme.

Pourquoi Lisp devient-il le langage de l’intelligence artificielle ?

Lisp arrive au bon moment avec des mécanismes adaptés aux problèmes étudiés par les laboratoires d’IA : listes de longueur variable, symboles, arbres, récursion, fonctions manipulables, mémoire automatique et environnement interactif. L’article de McCarthy de 1960 cite déjà la vérification de preuves, la différentiation et l’intégration symboliques, la logique et l’Advice Taker parmi les usages visés.

Le langage se diffuse ensuite sur les machines utilisées par les grands laboratoires. Au MIT, les PDP-6 puis PDP-10 deviennent des plates-formes majeures pour Lisp et l’intelligence artificielle. Des systèmes de calcul symbolique comme Macsyma, des programmes de recherche, des outils de démonstration et de nombreux environnements expérimentaux sont développés dans cet univers.

Le Computer History Museum résume cette place en qualifiant Lisp de véritable lingua franca de l’IA de cette période. Son importance ne vient donc pas d’une obligation institutionnelle : le langage correspond simplement très bien au type de programmes que les chercheurs veulent écrire.

Quand on construit un ordinateur pour Lisp

À mesure que les programmes d’IA grossissent, les limites des machines généralistes deviennent plus visibles. Au MIT AI Lab, Richard Greenblatt, Thomas Knight et d’autres ingénieurs explorent une solution radicale : au lieu d’adapter Lisp à un ordinateur conçu pour autre chose, pourquoi ne pas construire un ordinateur adapté à Lisp ?

Greenblatt décrit en 1974 un projet de Lisp machine. Quelques années plus tard, les prototypes du MIT débouchent sur des stations de travail spécialisées. Elles ne se contentent pas d’accélérer l’exécution : elles proposent un environnement très intégré où l’on peut écrire, inspecter, compiler et déboguer de grands programmes de manière interactive.

Au début des années 1980, cette technologie est commercialisée notamment par Symbolics et Lisp Machines, Inc. Pendant quelques années, les Lisp machines incarnent une informatique haut de gamme destinée à l’IA. Leur marché restera spécialisé et perdra ensuite de son intérêt face à la progression rapide des stations de travail généralistes, mais leurs environnements de développement ont marqué toute une génération de programmeurs.

Lisp n’est pas un seul langage

Le nom Lisp désigne rapidement une famille. Les implémentations se multiplient et chacune adapte le langage à son environnement.

Maclisp, développé au MIT, joue un rôle central dans les années 1960 et 1970. Interlisp, issu des travaux de BBN puis développé à Xerox PARC, met fortement l’accent sur l’environnement interactif, l’édition et le débogage.

En 1975, Gerald Jay Sussman et Guy Steele présentent Scheme. Ce dialecte plus petit met notamment en avant la portée lexicale des variables, les fonctions comme valeurs de première classe et une utilisation particulièrement propre de la récursion terminale.

Au début des années 1980, la multiplication des dialectes devient un problème pour les gros logiciels. Plusieurs équipes cherchent alors un terrain commun. Le résultat est Common Lisp, décrit en 1984 par Guy Steele puis normalisé par l’ANSI en 1994. Le but n’est pas de remplacer toute la famille Lisp, mais de fournir une base stable et portable pour des applications importantes.

De Lisp à Emacs, AutoCAD et Clojure

La famille ne reste pas enfermée dans les laboratoires d’intelligence artificielle. Emacs Lisp, fortement inspiré de Maclisp, devient le langage d’extension de GNU Emacs. Une grande partie du comportement de l’éditeur peut ainsi être modifiée par l’utilisateur avec le même langage qui sert à l’application elle-même.

Dans les années 1980, Autodesk choisit Lisp pour étendre AutoCAD. AutoLISP permet d’automatiser des tâches de dessin et d’ajouter des commandes spécialisées. Il est encore pris en charge aujourd’hui dans les produits AutoCAD.

En 2007, Rich Hickey présente Clojure, un Lisp destiné à la JVM. Le langage conserve le principe du code représenté comme des données et les macros, mais l’associe à des structures persistantes immuables et à des mécanismes conçus pour la programmation concurrente. Lisp n’est donc pas seulement un langage historique : c’est une idée de langage qui continue d’être réinterprétée.

Les limites : une élégance qui demande un apprentissage

La syntaxe uniforme de Lisp simplifie son analyse par la machine, mais elle déroute souvent le débutant. Un programme important peut contenir beaucoup de parenthèses et la notation préfixée demande un temps d’adaptation.

La famille Lisp a aussi longtemps souffert de sa fragmentation. Maclisp, Interlisp, Scheme, Common Lisp, Emacs Lisp ou AutoLISP partagent des idées communes sans être interchangeables. Un programme écrit dans l’un ne fonctionne pas automatiquement dans les autres.

Les premières implémentations étaient en outre peu performantes pour le calcul numérique par rapport à FORTRAN. McCarthy reconnaissait déjà cette faiblesse dans l’histoire du langage. Les compilateurs modernes ont largement changé la situation, mais l’image d’un Lisp lent et gourmand en mémoire s’est installée durablement.

Enfin, la puissance des macros possède son revers. Elles permettent d’adapter le langage au problème, mais un programme abusant de constructions très personnelles peut devenir difficile à lire pour quelqu’un qui ne connaît pas ces extensions.

Un héritage beaucoup plus large que ses parenthèses

L’influence de Lisp ne se mesure pas seulement au nombre de programmes encore écrits en Common Lisp ou en Scheme. Plusieurs idées devenues ordinaires dans la programmation moderne ont été explorées très tôt et de manière systématique dans son écosystème : gestion automatique de la mémoire, fonctions comme valeurs, récursion, développement interactif, représentation structurée des programmes et macros capables de transformer le code.

Toutes ces idées n’ont pas été inventées isolément par Lisp. Certaines viennent des mathématiques, d’autres existaient dans des travaux antérieurs. Lisp les a cependant réunies dans un système cohérent et utilisable sur de vraies machines à une époque où la plupart des langages de programmation suivaient une direction très différente.

En 1980, John McCarthy expliquait la longévité de Lisp par le fait que le langage avait trouvé une combinaison particulièrement stable de mécanismes. Plus de soixante ans après les premières implémentations, le constat reste pertinent : les dialectes ont changé, les machines n’ont plus rien à voir avec l’IBM 704, mais l’idée centrale est toujours reconnaissable.

Derrière les parenthèses se trouve une proposition simple : si un programme est représenté comme une structure de données, le langage peut aussi devenir un outil pour examiner, transformer et construire ses propres programmes. C’est cette idée, bien plus que sa syntaxe, qui donne à Lisp sa place particulière dans l’histoire de l’informatique.

Sources principales

À lire aussi sur Histoire de l’Informatique

Publications similaires

  • COBOL

    COBOL, acronyme de Common Business-Oriented Language, est un langage de programmation créé à partir de 1959 pour répondre à un problème devenu crucial : comment écrire des programmes de gestion capables de fonctionner sur des ordinateurs provenant de constructeurs différents ? À la fin des années 1950, IBM, UNIVAC, RCA, Honeywell, Burroughs et d’autres fabricants…

  • Le langage C

    Au début des années 1970, programmer un système d’exploitation signifie encore travailler presque entièrement en assembleur. Cette méthode permet de contrôler précisément la machine, mais elle exige beaucoup de temps et lie étroitement le programme au processeur pour lequel il a été écrit. Changer d’ordinateur oblige souvent à reprendre une grande partie du travail. Aux…

  • Fortran

    FORTRAN, contraction de FORmula TRANslation (« traduction de formules »), est l’un des langages les plus importants de l’histoire de l’informatique. Développé chez IBM sous la direction de John Backus, il permet aux scientifiques et aux ingénieurs d’écrire leurs calculs sous une forme beaucoup plus proche des mathématiques que des instructions d’une machine.Lorsque le premier…

  • Speedcoding

    En 1953, alors que l’informatique n’en est encore qu’à ses débuts, IBM introduit un système de programmation qui va profondément transformer la manière d’utiliser les ordinateurs scientifiques : Speedcoding. Speedcoding est un système de programmation scientifique développé par IBM en 1953 pour l’IBM 701, sous la supervision de John W. Backus. Il simplifie l’écriture des…

  • BCPL

    BCPL signifie Basic Combined Programming Language : une version simplifiée de CPL, conçue pour écrire des compilateurs et des logiciels système plus faciles à transporter d’une machine à l’autre. Au milieu des années 1960, les langages de programmation deviennent plus expressifs, mais leurs compilateurs restent souvent longs et difficiles à adapter. Un langage peut être…

  • BASIC

    Le BASIC est un langage de programmation créé en 1964 au Dartmouth College par John G. Kemeny et Thomas E. Kurtz pour rendre l’informatique accessible aux débutants. Son nom signifie Beginner’s All-purpose Symbolic Instruction Code. Associé dès l’origine au temps partagé, BASIC permet à un étudiant de saisir quelques lignes, lancer son programme, voir immédiatement…