Apprenez le langage de programmation Lisp en 2021
Une grande partie du code Lisp se cache dans de grandes bases de code, il est donc judicieux de se familiariser avec le langage.
Lisp a été inventé en 1958, ce qui en fait le deuxième langage de programmation informatique le plus ancien. Il a engendré plusieurs dérivés modernes, notamment Common Lisp, Emacs Lisp (Elisp), Clojure, Racket, Scheme, Fennel et GNU Guile.
Les personnes qui aiment réfléchir à la conception de langages de programmation aiment souvent Lisp en raison de la façon dont sa syntaxe et ses données partagent la même structure : le code Lisp est essentiellement une liste de listes, et son nom est l'acronyme de LISt Processing. . Les personnes qui aiment réfléchir à l’esthétique des langages de programmation détestent souvent Lisp en raison de son utilisation fréquente de parenthèses pour la définition de la portée ; en fait, c'est une blague courante que Lisp signifie Beaucoup de parenthèses superflues irritantes.
Que vous aimiez ou détestiez ses philosophies de conception, Lisp est un aperçu intéressant du passé et, grâce à Clojure et Guile, du futur. Vous pourriez être surpris de la quantité de code Lisp qui se cache dans les grandes bases de code d'un secteur donné, c'est donc une bonne idée d'avoir au moins une familiarité passagère avec le langage.
Installer Lisp
Il existe de nombreuses implémentations de Lisp. Les versions open source populaires incluent SBCL, GNU Lisp et GNU Common Lisp (GCL). Vous pouvez installer n'importe lequel d'entre eux avec le gestionnaire de paquets de votre distribution, mais pour cet article, j'utilise clisp
.
Sous Fedora Linux :
$ sudo dnf install clisp
Sur Debian :
$ sudo apt install clisp
Pour macOS, vous pouvez utiliser MacPorts ou Homebrew :
$ sudo port install clisp
Pour Windows, vous pouvez soit utiliser clisp
sur Cygwin, soit télécharger un binaire GCL depuis gnu.org/software/gcl.
Même si j'utilise la commande clisp
, la plupart des principes de cet article s'appliquent à n'importe quel Lisp. Si vous choisissez d'utiliser une implémentation Lisp différente, la commande pour exécuter le code Lisp est différente de celle que j'utilise dans cet article (gcl
ou sbcl
au lieu de clisp
, par exemple) mais tout le reste est pareil.
Traitement des listes
L'unité de base du code source Lisp est une expression, qui est écrite sous forme de liste. Par exemple, il s'agit d'une liste d'un opérateur (+
) et de deux entiers (1
et 2
) :
(+ 1 2)
C'est aussi une expression Lisp, utilisant un symbole (+
) qui s'évalue en une fonction (addition) et deux arguments (1
et 2
). Vous pouvez exécuter cette expression et d’autres dans un environnement Common Lisp interactif appelé REPL (read-eval-print loop). Si vous êtes familier avec IDLE de Python, REPL de Lisp devrait vous sembler quelque peu familier.
Pour lancer un REPL, lancez Common Lisp :
$ clisp
[1]>
À l'invite REPL, tapez quelques expressions :
[1]> (+ 1 2)
3
[2]> (- 1 2)
-1
[3]> (- 2 1)
1
[4]> (+ 2 3 4)
9
Les fonctions
Maintenant que vous connaissez la structure de base d'une expression Lisp, vous pouvez utiliser les fonctions Lisp de manière utile. La fonction print
prend n'importe quel argument que vous fournissez et l'affiche sur votre terminal, tandis que la fonction pprint
"pretty" l'imprime. Il existe d'autres variantes de la fonction d'impression, mais pprint
est sympa dans REPL :
[1]> (pprint "hello world")
"hello world"
[2]>
Vous pouvez créer vos propres fonctions avec defun
. La fonction defun
nécessite un nom pour votre fonction et tous les paramètres que vous souhaitez que votre fonction accepte :
[1]> (defun myprinter (s) (pprint s))
MYPRINTER
[2]> (myprinter "hello world")
"hello world"
[3]>
Variables
Vous pouvez créer des variables en Lisp avec setf
:
[1]> (setf foo "hello world")
"hello world"
[2]> (pprint foo)
"hello world"
[3]>
Vous pouvez imbriquer des expressions dans des expressions dans une sorte de pipeline. Par exemple, vous pouvez afficher joliment le contenu de votre variable après avoir invoqué la fonction string-upcase
pour convertir ses caractères en majuscules :
[3]> (pprint (string-upcase foo))
"HELLO WORLD"
[4]>
Lisp est typé dynamiquement dans le sens où vous n'avez pas besoin de déclarer les types de variables lors de leur définition. Lisp traite les entiers comme des entiers par défaut :
[1]> (setf foo 2)
[2]> (setf bar 3)
[3]> (+ foo bar)
5
Si vous souhaitez qu'un entier soit interprété comme une chaîne, vous pouvez le citer :
[4]> (setf foo "2")
"2"
[5]> (setf bar "3")
"3"
[6]> (+ foo bar)
*** - +: "2" is not a number
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead.
ABORT :R2 Abort main loop
Break 1 [7]>
Dans cet exemple de session REPL, foo
et bar
sont tous deux définis sur des nombres entre guillemets, donc Lisp les interprète comme des chaînes. Les opérateurs mathématiques ne peuvent pas être utilisés sur des chaînes, donc REPL passe en mode débogueur. Pour sortir du débogueur, appuyez sur Ctrl+D sur votre clavier.
Vous pouvez faire une introspection sur les objets en utilisant la fonction typep
, qui teste un type de données spécifique. Les jetons T
et NIL
représentent respectivement True et False.
[4]> (typep foo 'string)
NIL
[5]> (typep foo 'integer)
T
Le guillemet simple ('
) avant string
et integer
empêche Lisp d'évaluer (incorrectement) ces mots-clés en tant que variables :
[6]> (typep foo string)
*** - SYSTEM::READ-EVAL-PRINT: variable STRING has no value
[...]
C'est une façon abrégée de protéger les termes, normalement réalisée avec la fonction quote
:
[7]> (typep foo (quote string))
NIL
[5]> (typep foo (quote integer))
T
Listes
Sans surprise, vous pouvez également créer des listes en Lisp :
[1]> (setf foo (list "hello" "world"))
("hello" "world")
Les listes peuvent être indexées avec la fonction nth
:
[2]> (nth 0 foo)
"hello"
[3]> (pprint (string-capitalize (nth 1 foo)))
"World"
Quitter REPL
Pour terminer une session REPL, appuyez sur Ctrl+D sur votre clavier, ou utilisez le mot-clé quit
en Lisp :
[99]> (quit)
$
Script
Lisp peut être compilé ou utilisé comme langage de script interprété. Cette dernière est probablement l’option la plus simple lorsque vous débutez, surtout si vous êtes déjà familier avec Python ou les scripts shell.
Voici un simple script de lancer de dés écrit en GNU Common Lisp :
#!/usr/bin/clisp
(defun roller (num)
(pprint (random (parse-integer (nth 0 num))))
)
(setf userput *args*)
(setf *random-state* (make-random-state t))
(roller userput)
La première ligne indique à votre terminal POSIX quel exécutable utiliser pour exécuter le script.
La fonction roller
, créée avec defun
, utilise la fonction random
pour imprimer un nombre pseudo-aléatoire jusqu'au zéroième élément non inclus. de la liste num
. La liste num
n'a pas encore été créée dans le script, mais la fonction n'est exécutée que lorsqu'elle est appelée.
La ligne suivante attribue tout argument fourni au script au moment du lancement à une variable appelée userput
. La variable userput
est une liste, et c'est ce qui devient num
une fois passée à la fonction roller
.
L'avant-dernière ligne du script démarre une graine aléatoire. Cela fournit à Lisp suffisamment d’entropie pour générer un nombre principalement aléatoire.
La dernière ligne appelle la fonction personnalisée roller
, fournissant la liste userput
comme seul argument.
Enregistrez le fichier sous dice.lisp
et marquez-le comme exécutable :
$ chmod +x dice.lisp
Enfin, essayez de l'exécuter en lui fournissant un nombre maximum parmi lequel choisir son nombre aléatoire :
$ ./dice.lisp 21
13
$ ./dice.lisp 21
7
$ ./dice.lisp 21
20
Pas mal!
Vous remarquerez peut-être que votre dé émulé a une valeur pontentielle de 0 et n'atteint jamais le nombre maximum que vous lui fournissez en argument. En d’autres termes, ce script ne lance jamais 20 sur un dé à 20 faces (sauf si vous comptez 0 comme 20). Il existe une solution simple à ce problème, et vous n'avez besoin que des connaissances acquises grâce à cet article pour le faire. Pouvez-vous corriger ce bug ?
Apprendre le Lisp
Que vous puissiez imaginer utiliser Lisp comme langage utilitaire pour des scripts personnels, pour faire avancer votre carrière ou simplement comme une expérience amusante, vous pourrez découvrir des utilisations particulièrement inventives lors du Lisp Game Jam annuel (la plupart des soumissions sont open source, vous pouvez donc voir le code pour apprendre de ce que vous jouez).
Lisp est un langage amusant et unique avec une base de développeurs en constante augmentation et suffisamment de dialectes historiques et émergents pour satisfaire les programmeurs de toutes les disciplines.