Multiple implementations (JS, Wasm, C) of a Lisp.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
6.0 KiB

#+TITLE: Le LISP et son implementation
#+AUTHOR: Gabriel Pariat
* Intro
Bien le bonjour!
Music Land of lisp: https://youtu.be/HM1Zb3xmvMc
* Play Game!
Jouons à un petit [[https://lisp.pariatech.com][Jeux d'aventure]]!
* C'est quoi le LISP?
Le LISP est une famille de language vielle comme le chemin.
Datant de 1958 et on parle du deuxieme plus vieux language haut-niveau, le plus
vieux étant FORTRAN de juste un ans.
Les LISP les plus populaires sont Racket, Common Lisp, Scheme et Clojure.
On manque pas de choix, et ils ont tous leurs petits partularités.
Mais encore on parle pas de la centaine d'autre implémentation de LISP,
qui doit existé, ont éxisté.
Je vais vous montré pourquoi il y a autant d'implémentation de cette famille
de language.
* Comment ça marche?
** Les Grande lignes
L'intépréteur a sont plus simple à cette structure.
#+begin_export ascii
TEXT => Reader - Génére l'arbre du code à partir du text brute.
||
\/
Evaluator - Évalue l'arbre pour en obtenir un résultat.
||
\/
TEXT <= Printer - Transform le résultat en du text pour l'usagé.
#+end_export
** Reader
Le travail du Reader est de créer un arbre à partir du text.
*** Les pairs
Un arbre est composé de pairs. Et des pairs enchainé ensemble donne une liste.
#+begin_example
(+ 1 2 (* 3 4)) => (+ . (1 . (2 . ((* . (3 . (4 . nil))) . nil))))
/\
/ \
+ /\
/ \
1 /\
/ \
2 /\
/ \
/\ nil
/ \
* /\
/ \
3 /\
/ \
4 nil
#+end_example
*** Parsing
La syntax très simple du LISP nous aide énormement pour cette partie.
Tout ce qui nous importe c'est les parenthéses et les espaces.
Tout le reste n'est que des symbols. Oui, mais sauf ci c'est un chiffre...
À l'ouverture d'une parenthése détermine qu'on ouvre une paire.
Et quand on referme cette parenthése on termine une liste. Chaque
espace délimite les symbols.
*** Mais est-ce vraiment si simple?
Non pas vraiment, j'ai menti...
Le seul petit caveat c'est les pairs. En gros les pairs individuel.
Celle ci sont composé de deux symbols séparés par un point.
#+begin_example
(1 . 2)
#+end_example
Sinon il y d'autre "Sugar Syntax" populaire comme par example:
#+begin_example
' => quote
` => quasiquote
, => unquote
,@ => unquote-splicing
"" => string
[] => vector
{} => hashmap
etc...
#+end_example
La liste peux grandir autant qu'on veux. Mais sans rentré dans
les détails mais souvent les implémenteurs sont lache et
implémente dans le language la pausibilité d'ajouter des
macros à la lecture pour ajouter ses propres "Sugar Syntax".
** Evaluator
Maintenant qu'on a notre arbre, c'est le temps de le résoudre.
Pour cela faut le parcourir et aussi savoir l'ordre d'opération.
*** Parcour et l'ordre
Le parcour n'est rien d'autre qu'une récursion.
Mais avec quelques petits caveats.
Quand on parcour l'arbre et on tombe sur une valeur qui est une paire.
Il faut parcourir le premier élément de cette paire.
Par le fait cet élément va etre évalué le premier.
Il à deux possibilité de résultat:
**** Opération spéciale
Suivre les instructions de celle-ci. Comme example,
IF: évalue la conditions et ensuite la bonne branche.
**** Fonction
Évalué chaque arguments de celle-ci et ensuite évalué le résultat de la
fonction.
*** Environment
Bon c'est bien beau s'avoir quoi faire, mais faut encore savoir ce que
nos symbols veullent dire.
C'est la que l'environment vien en jeux. Il nous permet d'associer une valeur
à un symbole. Par valeur on parle de n'importe quoi, une fonction, un chiffre,
une string, une liste, etc...
Donc quand on arrive sur une feuille de notre arbre on va voir dans cette
table pour trouvé la valeur de notre symbol.
C'est dans lui qu'on va stocker aussi les fonctions et les variables que
notre code va généré.
*** Bonus: Macros
Si on parle LISP on ne peux pas ne pas parlé des macros.
C'est ce qui donne la famille de language un edge considerable sur les autres.
Ne voyez pas les Macros en C/C++ qui ne sont pas plus que de la substitution.
Ni mêmes les templates de C++ qui tent dire un autre language a part entiere du C++.
Mais du LISP qui génére du LISP.
Oui, vous écrivez du code, le même que vous utilisé normalement, mais celui ci va être appelé
avant l'évaluation pour générer du code qui lui va être évalué.
Je vais être honête ça été un petit brainfuck pensé comment implémenté cela,
une évaluation avant une évaluation, mais qui a besoin d'être évalué...
Mais finalement c'est pas compliqué.
** Printer
En gros le printer, c'est comme le reader, mais à l'envers.
Tu parcour l'abre que l'évaluateur à retourné et converti chaque valeur
en ça forme texte.
** Loop
Et quand tu met tout ça dans une loop, tu a un REPL.
Ce que vous voyez sur mon site c'est un REPL.
Si vous installer un interpréteur Common Lisp, comme par example SBCL et vous le lancer.
Vous allez voir un REPL.
Le REPL c'est cool parceque tu peux jouer avec l'environment pendant que ton programme roule.
Tu veux tester une fonction, let's go! Tu veux changer la vitesse que ton personnage bouge dans ton jeux,
Let's go! Y'a une erreur dans une de tes fonctions et tu ne veux pas repartir ton programme, pas de
problème amigos, juste fourni moi la version corrigé!
* Questions?
Vous avez des questions?
Vous avez aimez?
Le code ce trouve sur https://git.pariatech.com/pt-lisp.
C'est sur la branche: refactoring. Je n'ai pas encore merger dans master, j'ai des bugs à régler avant...
Si vous voulez en apprendre plus je recommende le livre LAND OF LISP par Conrad Barski.
Extra chanson sur la programmation:
Round worm, Eternal Flame: https://youtu.be/u-7qFAuFGao