- L’essentiel de Lisp n’est pas sa syntaxe à parenthèses, mais une manière de penser qui consiste à étendre le langage pour l’adapter au problème ; sa vraie valeur n’apparaît qu’en maîtrisant aussi le REPL, les packages, les symboles, les conditions et les redémarrages
- Grâce à l’homoiconicité, où le code comme les données sont tous deux représentés sous forme de listes, les macros peuvent manipuler le code comme une donnée avant son évaluation afin de créer de nouvelles structures de contrôle et des abstractions syntaxiques
- Même si Common Lisp ne possède pas de
while, on peut l’ajouter avec defmacro, alors qu’une imitation via une fonction échoue car les arguments y sont évalués immédiatement et body devient une valeur au lieu d’être du code
- Le développement en Lisp se rapproche d’un développement piloté par le REPL, où l’on continue d’évaluer du code dans un processus en cours d’exécution et où l’on peut faire évoluer le programme sans interruption en redéfinissant fonctions, macros et variables
- Quand l’extensibilité du langage se combine à un système live, on peut créer des logiciels extensibles qui exposent des DSL internes à l’utilisateur ; AutoLISP et Emacs en sont des exemples représentatifs
Une autre sensibilité de programmation exigée par Lisp
- Les programmeurs qui découvrent Lisp pour la première fois sont souvent déroutés par sa syntaxe très parenthésée, son indentation particulière et la façon dont
format prend la sortie standard comme premier argument
- Pour apprendre Lisp, il ne suffit pas de lire du code : il faut aussi manipuler les packages et les symboles, créer un projet, importer des bibliothèques, utiliser le REPL, ainsi que les conditions et les redémarrages
- Le changement le plus profond apparaît dans la manière de construire les algorithmes
- Lisp rend possibles des choses difficiles à faire dans d’autres langages, et cela modifie aussi la forme des algorithmes
- On commence par faire grandir le langage en fonction du problème, puis on écrit le programme dans ce langage ainsi enrichi
- Le paradoxe de Blub explique pourquoi un programmeur n’ayant utilisé que des langages moins puissants a du mal à percevoir les atouts de Lisp
Un langage extensible
- Lisp peut s’étendre lui-même, et les experts Lisp parlent pour cela de programmable programming language
- L’outil central est la
macro
- Contrairement aux macros de C, Rust ou Swift, elle ne se limite pas à supprimer du code répétitif
- Les macros Lisp peuvent créer de nouveaux composants qui deviennent une partie du langage
- Common Lisp ne fournit pas d’opérateur
while de base, mais on peut l’ajouter soi-même avec defmacro
(defmacro while (condition &body body)
`(loop while ,condition do
(progn ,@body)))
- Cette macro
while exécute les différentes instructions de body tant que condition est vraie
loop est une macro permettant d’écrire des itérations complexes
progn exécute plusieurs expressions dans l’ordre et renvoie le résultat de la dernière
- En pratique, on peut donc écrire
(while ...) au lieu de (loop while ... do (progn ...)), ce qui raccourcit le code et lui donne une structure proche du while de C
La différence décisive entre macro et fonction
- Si l’on essaie de reproduire le même comportement avec une fonction
fake-while, cela échoue
(defun fake-while (condition body)
(loop while condition do
(funcall body)))
- Lors d’un appel à
fake-while, les arguments sont d’abord évalués
condition devient la valeur vraie t
- Dans le
progn, (print counter) s’exécute et (decf counter) renvoie 2
body n’est plus un bloc de code, mais la valeur 2
- Ensuite,
funcall attend une fonction, mais reçoit 2, ce qui provoque une erreur de type du genre The value 2 is not of type FUNCTION
- La macro
while, elle, préserve condition et body sans les évaluer immédiatement
- On peut vérifier son expansion avec
macroexpand-1
- Le compilateur reçoit alors du code développé sous la forme
(LOOP WHILE ... DO (PROGN ...))
- Contrairement à une fonction, une macro ne pré-évalue pas ses arguments et les traite comme des données pures, ce qui rend possible ce type de transformation
Listes, s-expressions, homoiconicité
- Un programme Lisp est constitué d’une suite de symbolic expressions, c’est-à-dire de s-expressions
- Les s-expressions se divisent en deux catégories
- les atomes (atom) : unités de données comme les nombres, les chaînes ou les symboles
- les listes (list) : collections contenant des atomes ou d’autres listes
- Le nom Lisp vient de LISt Processing, et les instructions qui composent les programmes sont elles aussi représentées sous forme de listes
- En Lisp, la liste est à la fois la structure de données principale et la manière d’écrire le code
- Cette propriété selon laquelle code et données sont tous deux représentés comme des listes s’appelle l’homoiconicité (homoiconicity)
- Une même liste
(+ 1 2) se comporte différemment selon qu’elle est évaluée ou non
(+ 1 2) est évalué comme du code et renvoie 3
'(+ 1 2) n’est pas évalué et renvoie la liste de données telle quelle
- Lisp utilise la notation polonaise en plaçant le nom de la fonction comme premier élément de la liste, suivi des arguments
- Comme la frontière entre code et données est ténue, les macros peuvent transformer le code source et permettre d’écrire des programmes qui écrivent des programmes
Les abstractions de code créées par les macros
- Étendre le langage permet de créer, pour un domaine précis du programme, de nouveaux composants plus expressifs
- Le boilerplate répétitif peut être remplacé par des macros sur mesure, ce qui réduit le code et fait gagner du temps
- On peut créer de nouvelles structures de contrôle pour piloter l’accès aux ressources et l’évaluation des forms
- Les macros génèrent du code, améliorent les performances et fournissent des abstractions syntaxiques qui masquent du code complexe et sujet aux erreurs
Lisp comme système live
- Lisp est traité moins comme un simple langage de programmation que comme un système live en cours d’exécution
- Dans les langages plus classiques, on écrit souvent du code dans l’éditeur, puis on compile et on exécute pour observer, tester et déboguer
- En Lisp, on commence par lancer un processus Lisp, s’y connecter via le REPL, puis charger le projet dans ce processus
- REPL signifie Read-Eval-Print Loop : c’est un environnement interactif où l’on évalue du code et voit immédiatement le résultat
- Il sert de fenêtre sur le processus Lisp qui exécute actuellement le programme
- Les développeurs Lisp continuent à évaluer du code directement dans le processus en cours d’exécution et vérifient aussitôt les résultats dans le REPL
- test de fonctions individuelles
- requêtes à la base de données
- inspection de variables
- débogage, entre autres, peuvent aussi se faire dans le REPL
- Un processus Lisp n’a pas besoin d’être arrêté et peut rester vivant pendant des semaines
- Les fonctions, macros et variables sont continuellement définies et redéfinies dans la mémoire interne qu’est l’environnement (environment) ; cette manière de travailler est appelée développement piloté par le REPL
Le hot reloading en Lisp
- Dans le frontend web, l’expérience d’un hot reload du code JavaScript via la sauvegarde d’un fichier ou le rafraîchissement de la page est courante
- En général, le hot reloading repose sur des outils et techniques séparés, comme la surveillance de fichiers, la recompilation des modules modifiés ou l’injection des changements via WebSocket
- Toutes les couches logicielles n’offrent pas le même niveau de hot reloading
- certains frameworks backend exigent une recompilation
- les environnements de développement desktop et mobile sont plus hétérogènes
- les langages de bas niveau nécessitent souvent une compilation complète à chaque fois
- En Lisp, le hot reloading n’est pas un outil distinct : il découle naturellement de l’évaluation de code dans un environnement live
- lorsqu’on redéfinit un symbole, fonctions, données et macros utilisent toutes la nouvelle définition
- il devient moins nécessaire d’arrêter et de compiler, d’exécuter les tests séparément ou d’utiliser un débogueur spécial
- Programmer en Lisp ressemble moins à assembler un programme qu’à le faire évoluer
Des logiciels extensibles
- L’extensibilité du langage et le système live facilitent la création de logiciels extensibles en Lisp
- Un programme desktop classique s’étend généralement via des plugins ou un langage de script
- les développeurs doivent concevoir et maintenir le système d’extension
- les utilisateurs doivent apprendre une API spécifique pour écrire des plugins ou des extensions
- En Lisp, encapsuler le comportement dans des macros et le rendre réutilisable conduit naturellement à écrire des DSL
- Pour rendre un logiciel extensible, il suffit alors d’exposer aux utilisateurs le DSL créé en interne
- Dans l’exemple d’un serveur CMS, on peut exposer aux utilisateurs une macro
html pour générer des pages web côté serveur
- les utilisateurs peuvent continuer à utiliser telles quelles les variables Lisp, les boucles
dolist et le formatage de chaînes avec format
- il n’est pas nécessaire d’apprendre une syntaxe séparée comme
{{ user_name }} ou {% for %}, contrairement aux langages de template traditionnels
- Ce DSL hérite directement des conditionnels de Lisp, de la récursivité, des fonctions d’ordre supérieur et de la capacité de débogage pas à pas via le REPL
- Dans l’exemple d’un logiciel de graphes mathématiques, on peut exposer un DSL pour les formules et le tracé, afin que l’utilisateur dessine courbes et points avec un code concis
Exemples concrets et place de Lisp
- AutoCAD utilise AutoLISP pour automatiser les tâches répétitives et générer des géométries complexes
- Emacs, en grande partie implémenté dans son propre dialecte Lisp, est un éditeur de texte hautement extensible
- lecteur PDF
- navigateur web
- client e-mail
- lecteur RSS
- multiplexeur de terminaux
- client Git
- lecteur de musique
- client de chat
- tableur
- client IRC
- et même gestionnaire de fenêtres de bureau, parmi les extensions mentionnées
- R. M. Stallman estime que Lisp est un langage qui aide à comprendre ce que signifient un langage de programmation puissant et élégant
- L’espoir de voir Lisp devenir un jour un langage généraliste largement adopté ne s’est pas réalisé, et cela semble peu probable à l’avenir
- Malgré cela, Lisp a survécu depuis les années 1960 et est devenu, après Fortran, le plus ancien langage de programmation encore en activité
- La valeur de Lisp ne vient pas d’une seule fonctionnalité comme l’extensibilité, l’environnement interactif ou le REPL, mais de leur combinaison
1 commentaires
Avis sur Hacker News
La programmation repose sur une tension entre le côté lumineux et le côté obscur
Le côté lumineux cherche à empêcher le programmeur de faire des erreurs : supprimer
goto, ajouter des types statiques, rendre certains bugs impossibles à exprimer, etc.Le côté obscur, lui, donne du pouvoir au programmeur : macros, surcharge d’opérateurs, code auto-modifiant, expressions régulières sur plusieurs lignes, tout est permis.
Lisp est clairement du côté obscur dans la mesure où le programmeur peut tout faire, et pourtant il est aussi respecté par les programmeurs du côté lumineux, ce qui est intéressant. C’est peut-être parce que la simplicité du langage lui donne un caractère platonicien, presque impossible à corrompre, ou peut-être parce que Lisp est si pur qu’il englobe les deux côtés, comme un dieu ayant engendré l’univers de la programmation
On ne choisit pas toujours avec qui l’on travaille, ni le niveau de compétence au sein de l’équipe. Quand un collègue moins expérimenté commet une erreur, plus le langage est permissif, plus les conséquences peuvent être importantes
C’est pourquoi il faut des revues de code, mais cela transforme alors les programmeurs expérimentés en enseignants. Une partie du temps passé à faire progresser les autres programmeurs est en quelque sorte gaspillée, parce que les programmeurs entrent et sortent de l’équipe en permanence. L’IA pourrait changer cette dynamique
Au fond, l’essentiel est de conserver une petite équipe très compétente, mais la politique d’entreprise rend cela difficile. Par exemple, on ajoute souvent des développeurs pour réduire le bus factor ou raccourcir les délais de livraison
Des systèmes à haute fiabilité sont aussi écrits en Erlang, qu’on peut voir, en plissant les yeux, comme un autre dialecte de Lisp. Il existe même LFE, une version en S-expressions d’Erlang à la sauce Lisp
Le cœur de la fiabilité d’Erlang ne réside pas dans une prévention exceptionnelle des erreurs, mais dans la récupération après erreur. J’aime bien, cela dit, cette classification lumineux/obscur
Même sans types statiques et avec des macros qui peuvent devenir un joyeux bazar, la base de pensée déclarative et fonctionnelle est bien plus forte, ce qui offre un meilleur point de départ pour penser et raisonner plus clairement sur les programmes
La distinction lumineux/obscur semble trop simplificatrice. L’équilibre des langages de programmation est un sujet très complexe et très intéressant
Après des années à expérimenter plusieurs langages, j’en suis arrivé à la conclusion que tout dépend du contexte d’utilisation, des préférences personnelles et des objectifs. Il n’existe pas de « meilleur langage de programmation de tous les temps », ni même de « meilleur pour la programmation côté lumineux » ou « meilleur pour la programmation côté obscur »
Dans la peinture aussi, il n’existe pas de côté lumineux ou obscur. Il y a certes des tableaux plus grands que d’autres, mais il n’existe pas de « meilleur tableau » que tout le monde trouverait plus beau que tous les autres
https://en.wikipedia.org/wiki/Malbolge
https://en.wikipedia.org/wiki/Clean_(programming_language)
https://en.wikipedia.org/wiki/K_(programming_language)
Ces derniers mois, d’excellents nouveaux éditeurs et outils sont sortis, il ne faut pas les manquer
Mine est une application à téléchargement unique qui fournit tout le nécessaire pour expérimenter un flux de développement interactif et incrémental, y compris le hot reloading et le débogage à la volée. C’est pour CL et Coalton
https://coalton-lang.github.io/20260424-mine/
OLIVE est un plugin artisanal pour VSCode, et ICL est un nouveau REPL pour terminal et navigateur avec des fonctionnalités avancées. En bonus, il y a aussi un kernel JupyterLite basé sur JSCL, qui fonctionne 100 % dans le navigateur
Tout est visible ici : https://lispcookbook.github.io/cl-cookbook/editor-support.ht...
mine. Il y a un lien ?Il semble y avoir un bug de coloration syntaxique sur le site. Les extraits de code inclus dans le texte apparaissent en noir, et on ne peut voir le vrai texte qu’en les sélectionnant à la souris
Je vois le même bug sur Chrome desktop et Safari sur iPad
La solution de contournement consiste à ouvrir un élément de code dans le débogueur du navigateur et à ajouter
color: whiteau style:not(pre) > codeIl existe beaucoup de textes qui font l’éloge des avantages de Lisp. J’aimerais aussi voir des textes qui critiquent posément Lisp, ses idées et sa place dans l’écosystème des langages
Ce type de texte, ou les billets de PG référencés ici, revient au fond à quelque chose de proche de « ceux qui savent, savent ». J’en comprends l’attrait, et je comprends aussi les affirmations explicites et implicites de cet article
La programmation informatique a beaucoup mûri au cours des 60 dernières années. J’aimerais voir davantage de textes proposant un examen plus réfléchi
Le deuxième défaut est qu’il peut engloutir pendant des années le temps de gens tout à fait compétents, sans que le résultat justifie cet investissement. Quelque chose comme Python suffit aussi. Je me dis que j’aurais préféré consacrer l’essentiel du temps passé sur Lisp à autre chose
Clojure, Clojurescript, Clojure-Dart, Fennel, Jade, Jank, Jolt et Coalton sont des langages relativement récents et continuent d’évoluer aujourd’hui. Ce ne sont que ceux qui me viennent à l’esprit, il y en a bien d’autres
D’une certaine manière, Lisp n’est pas un langage de programmation mais une idée. Il a influencé presque tous les langages de programmation que nous utilisons aujourd’hui, et continue de le faire. Il est difficile de critiquer « posément » une idée, un peu comme critiquer la théorie des groupes. En revanche, on peut discuter des avantages et inconvénients d’implémentations particulières de cette idée
async/awaitstandardisé. La norme n’a pas été mise à jour depuis 1995, donc cela ne risque probablement pas d’arriverPour certaines personnes, il exerce un attrait mental. J’ai envie de le comparer à un genre musical vraiment de niche. Peu de gens l’aiment, mais ceux qui l’aiment l’aiment avec une grande intensité. C’est un peu le Stockhausen du monde de la programmation
Fondamentalement, c’est un fandom. Un fandom étonnamment durable, mais qui n’a jamais vraiment percé largement et qui a peu de chances de le faire à l’avenir. Sa position est même pire aujourd’hui. Si l’on est armé de LLM et qu’on ne s’intéresse pas particulièrement au code en lui-même, pourquoi demanderait-on spécifiquement d’écrire en Lisp ?
On fait du Lisp depuis si longtemps qu’on finit par ne plus apprécier correctement ses fonctionnalités. Puis, quand on voit avec stupeur et effroi des gens se saboter eux-mêmes dans des langages plus populaires et moins risqués économiquement, on ressent soudain à nouveau la valeur de Lisp
Sur le terrain commercial, les langages spécifiques au domaine sont un anti-pattern. Quelqu’un crée un langage spécifique au domaine mal documenté que lui seul comprend, puis s’en va
Les programmeurs qui arrivent ensuite doivent s’efforcer de déchiffrer ce langage bizarre. Il est presque toujours préférable d’utiliser des structures et fonctionnalités de langage standard. On lit le code bien plus souvent qu’on ne l’écrit
Ce que l’on rejette vraiment est probablement le manque de transparence référentielle. Pour être honnête, c’est un problème dans beaucoup de langages, Lisp compris
Un bon exemple est la macro
LOOPde Common Lisp elle-même. Si l’usage qu’en fait quelqu’un est difficile à comprendre, on peut simplement demander à Lisp de l’étendre en appels primitifs plus verbeux sansLOOP, sans avoir besoin de comprendreLOOPdu tout. On peut même remplacer concrètement une formeLOOPpar le code développéC’est une différence essentielle avec la plupart des autres langages, où le code DSL est en réalité une structure de données interprétée
Les Lisps ont des aspects vraiment puissants et uniques, mais j’aimerais que ce type d’article n’inclue pas systématiquement le REPL et le hot reloading
Le REPL est depuis longtemps une condition de base dans les langages interprétés, et même dans certains langages compilés. Le hot reloading n’est ni unique ni particulièrement répandu. Comme il faut gérer l’état et les patchs, il y a une raison pour laquelle réinitialiser l’ensemble afin de faciliter le raisonnement est souvent considéré comme la bonne pratique
Cela permet donc un développement bien plus interactif que dans d’autres langages interprétés
Bien sûr, ce n’est pas parfait. Mais cela fonctionne très bien pour le type de changements qu’on apporte lorsqu’on itère sur l’expérience utilisateur
Cela dit, il vaut la peine de souligner qu’une grande partie des aspects avancés du hot reloading étaient déjà traités en Common Lisp. De même, le REPL n’est pas principalement un endroit où l’on tape directement du texte, mais une interface extrêmement puissante par laquelle l’image en cours d’exécution et les outils interagissent
Cela dit, je suis d’accord pour dire que le simple fait que ces choses existent n’a plus aujourd’hui rien de très spécial
Que faire si une définition de classe est remplacée lors d’un reload alors que les instances existantes sont toujours là ? Les dialectes de Common Lisp apportent des réponses utiles à ce type de question, mais ce n’est pas forcément le cas de tous les Lisps que l’on rencontre
Bash aussi prend en charge le hot reloading. J’ai déjà développé des modules mis à jour sur place en faisant simplement
sourcecomme ceci$ . /path/to/script.shSon utilité est limitée, mais si l’on part du principe qu’on va beaucoup s’en servir, cette limite commence à disparaître assez vite
Personnellement, j’ai déjà dépassé ce stade. J’ai utilisé Common Lisp, Forth et Haskell, et j’ai lu avec plaisir On Lisp et Let Over Lambda
Aujourd’hui, je pense que le meilleur langage de programmation est le Triage Calculus de Barry Jay. C’est proche de la logique combinatoire ou du lambda-calcul non typé
Mais contrairement au lambda-calcul, le Triage Calculus possède des mécanismes intégrés de citation et d’introspection, similaires à
CARetCDRde Lisp, ce qui permet d’ajouter facilement une vérification de types. Donc, dans TC, il suffit de construire la bonne abstraction pour obtenir n’importe quelle syntaxe souhaitée. C’est le véritable langage de programmation ultimeTC montre que la distinction entre, d’un côté, les fonctionnalités et la syntaxe du langage, et de l’autre, les définitions de fonctions/API de la bibliothèque standard ou du code utilisateur, est une fausse dichotomie. Chaque fois qu’on écrit du code destiné à être réutilisé, on ajoute quelque chose au langage. Tout cela peut être exprimé par un terme de TC
Tous les débats sur la syntaxe relèvent de l’habitude. Cela dit, la seule fonctionnalité syntaxique qui me manque vraiment dans TC est l’abstraction
let over lambda, parce qu’ordonner les combinateurs à la main est un peu pénibleArticle bien écrit
Avant, je pensais qu’un jour tout le monde utiliserait Lisp, et qu’avec de bons outils et bibliothèques tout deviendrait formidable. En fait, mon projet pour la retraite était de créer des bibliothèques de haute qualité pour les langages Lisp afin d’accélérer ce processus
L’essor de l’IA va-t-il mettre fin à ce rêve ? Est-ce qu’on a encore une fois résolu le problème en ajoutant davantage de bric-à-brac ? Au lieu qu’une IA superintelligente écrive du code dans le meilleur langage de programmation possible, va-t-on simplement lui faire déverser des tonnes de code Python jusqu’à ce que ça marche ?
Je ne sais pas si c’est important. Je voulais simplement un monde avec un peu d’élégance
« Jean-Marie Hullot, alors qu’il travaillait à l’INRIA, a créé “SOS Interface” pour Macintosh, écrit en Lisp, et ce fut le premier “interface builder” moderne »
https://denninginstitute.com/itcore/userinterface/GUIHistory...
Je me demande ce qui se serait passé si cela était devenu un produit Mac grand public, au lieu de basculer chez NeXT pour être utilisé avec Objective-C
LISP me convenait bien. Dans le cours de comparaison des langages à l’université, j’étais le seul à avoir fait tous les devoirs en LISP, et apprendre LISP m’a aussi beaucoup aidé à utiliser TeX
Ce que je voudrais, c’est un bon toolkit GUI open source, natif ou cross-platform, et un moyen de déployer facilement un projet sous forme de code compilé autonome
Les humains peuvent exprimer de bonnes idées avec les deux. Il vaut mieux voir le langage comme un outil. Une perceuse à percussion n’est pas supérieure à une simple perceuse rotative. Pour construire une terrasse, une perceuse à percussion sera peut-être plus adaptée, mais les deux peuvent faire le travail
Je pensais que ce serait https://web.archive.org/web/20120106121645/http://wiki.alu.o...
Ça me rappelle l’époque où je suivais comp.lang.lisp. C’était presque une sorte de feuilleton. Il n’y avait pas que de la magie de programmation, mais aussi beaucoup de personnages hauts en couleur et d’événements marquants