Ce qui rendait Lisp différent

Décembre 2001 (rév. Mai 2002)

(Cet article est né en réponse à quelques questions sur la liste de diffusion LL1. Il est maintenant intégré dans Revenge of the Nerds.)

Lorsque McCarthy a conçu Lisp à la fin des années 1950, c'était une rupture radicale avec les langages existants, le plus important étant Fortran.

Lisp incarnait neuf nouvelles idées :


1. Les conditionnelles. Une conditionnelle est une construction if-then-else. Nous les tenons pour acquises maintenant. Elles ont été inventées par McCarthy dans le cadre du développement de Lisp. (Fortran à cette époque n'avait qu'un goto conditionnel, étroitement basé sur l'instruction de branchement dans le matériel sous-jacent.) McCarthy, qui faisait partie du comité Algol, a introduit les conditionnelles dans Algol, d'où elles se sont répandues dans la plupart des autres langages.

2. Un type fonction. Dans Lisp, les fonctions sont des objets de première classe - ils sont un type de données comme les entiers, les chaînes, etc., et ont une représentation littérale, peuvent être stockés dans des variables, peuvent être passés comme arguments, et ainsi de suite.

3. La récursion. La récursion existait comme concept mathématique avant Lisp bien sûr, mais Lisp était le premier langage de programmation à la supporter. (C'est implicitement lié à la notion de fonctions comme objets de première classe.)

4. Une nouvelle conception des variables. Dans Lisp, toutes les variables sont effectivement des pointeurs. Les valeurs ont des types, pas les variables, et assigner ou lier des variables signifie copier des pointeurs, pas ce qu'ils pointent.

5. Le garbage-collection.

6. Des programmes composés d'expressions. Les programmes Lisp sont des arbres d'expressions, chacune renvoyant une valeur. (Dans certains Lisps, les expressions peuvent renvoyer plusieurs valeurs.) Cela contraste avec Fortran et la plupart des langages suivants, qui distinguent entre expressions et instructions.

Il était naturel d'avoir cette distinction dans Fortran parce que (sans surprise dans un langage où le format d'entrée était des cartes perforées) le langage était orienté ligne. Vous ne pouviez pas imbriquer des instructions. Et donc bien que vous ayez besoin d'expressions pour que les maths fonctionnent, il n'y avait pas d'intérêt à faire retourner une valeur par quoi que ce soit d'autre, parce qu'il ne pouvait rien y avoir pour l'attendre.

Cette limitation a disparu avec l'arrivée des langages à structure de blocs, mais à ce moment-là, il était trop tard. La distinction entre expressions et instructions était ancrée. Elle s'est propagée de Fortran à Algol et de là à leurs descendants.

Quand un langage est entièrement fait d'expressions, vous pouvez composer des expressions comme vous voulez. Vous pouvez dire soit (en utilisant la syntaxe Arc)

(if foo (= x 1) (= x 2))

ou

(= x (if foo 1 2))

7. Un type symbole. Les symboles diffèrent des chaînes en ce que vous pouvez tester l'égalité en comparant un pointeur.

8. Une notation pour le code utilisant des arbres de symboles.

9. Tout le langage toujours disponible. Il n'y a pas de réelle distinction entre le temps de lecture, le temps de compilation et le temps d'exécution. Vous pouvez compiler ou exécuter du code pendant la lecture, lire ou exécuter du code pendant la compilation, et lire ou compiler du code à l'exécution.

Exécuter du code au moment de la lecture permet aux utilisateurs de reprogrammer la syntaxe de Lisp ; exécuter du code au moment de la compilation est la base des macros ; compiler à l'exécution est la base de l'utilisation de Lisp comme langage d'extension dans des programmes comme Emacs ; et lire à l'exécution permet aux programmes de communiquer en utilisant des s-expressions, une idée récemment réinventée sous le nom de XML.


Lorsque Lisp a été inventé, toutes ces idées étaient très éloignées de la pratique de programmation ordinaire, qui était largement dictée par le matériel disponible à la fin des années 1950.

Avec le temps, le langage par défaut, incarné dans une succession de langages populaires, a progressivement évolué vers Lisp. Les points 1 à 5 sont maintenant répandus. Le point 6 commence à apparaître dans le courant dominant. Python a une forme du point 7, bien qu'il ne semble pas y avoir de syntaxe pour cela. Le point 8, qui (avec le point 9) est ce qui rend les macros Lisp possibles, est jusqu'à présent encore unique à Lisp, peut-être parce que (a) il nécessite ces parenthèses, ou quelque chose d'aussi mauvais, et (b) si vous ajoutez cette dernière incrémentation de puissance, vous ne pouvez plus prétendre avoir inventé un nouveau langage, mais seulement avoir conçu un nouveau dialecte de Lisp ; -)

Bien qu'utile aux programmeurs d'aujourd'hui, il est étrange de décrire Lisp en termes de sa variation par rapport aux expédients aléatoires adoptés par d'autres langages. Ce n'était probablement pas ainsi que McCarthy le concevait. Lisp n'a pas été conçu pour corriger les erreurs de Fortran ; il est plutôt apparu comme le sous-produit d'une tentative d'axiomatisation du calcul.