Pour mon projet actuel, je me suis retrouvé à devoir exécuter du lisp dans le navigateur¹. Plein d'optimisme, j'ai dégainé mon moteur de recherche préféré pour voir si il n'y avait pas un malade qui aurait déjà eu le même besoin que moi et bricolé un truc. Et ben il semblerait que plein de gens se soient penché sur la question.
Sélection de projets au hasard :
Pour l'instant, je n'ai joué qu'avec le premier. Les performances sont catastrophiques, mais il est très facile de dessiner dans un canvas webgl :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Demo LIPS</title>
<script src="https://cdn.jsdelivr.net/npm/@jcubic/lips@beta/dist/lips.min.js"></script>
<script type="text/x-scheme" bootstrap>
(let
((canvas_node (document.getElementById "canvas")))
(let
((ctx (canvas_node.getContext "2d")))
(do-iterator
(y (range canvas.height))
()
(do-iterator
(x (range canvas.width))
()
(begin
(set! ctx.fillStyle (format
"rgb(~a, ~a, 255)"
(/ (* x 255) canvas.width)
(/ (* y 255) canvas.width)))
(ctx.fillRect x y 1 1))))))
</script>
</head>
<body>
<canvas id="canvas" width="640" height="480"></canvas>
</body>
</html>
1: je bosse sur des trucs bizarres…
# Pourquoi lisp dans le navigateur ?
Posté par jtremesay (site web personnel) . Évalué à 4. Dernière modification le 04 mars 2023 à 21:31.
Ben je trouve que ça fait un format super élégant pour déclarer les scènes à rendre avec mon raytraceur :
La possibilité de profiter de la puissance du langage pour faire de la génération procédurale facile de scènes est un énorme plus.
[^] # Re: Pourquoi lisp dans le navigateur ?
Posté par dzecniv . Évalué à 3.
Carrément ! Je crois que c'est une illustration parfaite de ce fameux article: "une intuition pour la syntaxe Lisp": https://stopa.io/post/265
# Et pourquoi pas Web Assembly ?
Posté par tisaac (Mastodon) . Évalué à 4.
Je n'y connais rien et j'ai sans doute mal compris ton besoin mais ma première réaction a été de me demander pourquoi ne pas utiliser Web Assembly ? Je veux traduire ton code en WASM avant de le faie exécuter dans le browser (ce que ne semble pas faire lips-rs-wasm)
Est-ce parce qu'en fait, c'est autre chose que tu veux faire autre chose et que je n'ai pas compris ?
Ou est-ce parce qu'il n'y pas pas encore de solution viable pour créer du WASM à partir de LISP ?
Surtout, ne pas tout prendre au sérieux !
[^] # Re: Et pourquoi pas Web Assembly ?
Posté par jtremesay (site web personnel) . Évalué à 2.
ma réflexion a été "je veux lire des s-expr dans le navigateur", j'ai tapé "lisp in the browser" dans mon moteur de recherche préféré, et j'ai cliqué sur lips. Je n'ai pas poussé plus loin ma réflexion ou mes recherches :D
Mais effectivement, ça peut-être une piste intéressante.
Absolument aucune idée ! J'ai touché à lisp pour la première fois de ma vie cette semaine.
Je suis en train d'écrire un raytracer. Actuellement, il est en rust, utilise sdl pour faire le rendu et les scènes sont décrites en YAML. Mon but est à terme de le faire tourner dans le navigateur pour que les gens puissent facilement jouer avec et faire des scènes avec des maths dans ce style. Et je trouvais que lisp faisait un format de donnée élégant pour intégrer la logique nécessaire à l'écriture de ce genre de scènes pleines de maths, plus flexible que yaml et plus simple d'approche que les shaders webgl.
Donc là, à la base, je cherchais juste à lire une scène lisp depuis mon rust. Puis je me suis un peu égaré quand j'ai vu que je pouvais exécuter le lisp directement depuis le navigateur.
Et ça remet plein de choses en question. Parce que en fait, j'aime bien lisp, et j'aimerai bien ré-écrire le moteur dans ce langage. Mais d'un autre côté, j'ai déjà une base de code fonctionnelle dans un langage que je maîtrise mieux et qui je sais supporte wasm.
[^] # Re: Et pourquoi pas Web Assembly ?
Posté par Leirda . Évalué à 3.
J’ai l’impression qu’aujourd’hui en terme d’outillage et de performance c’est plus simple d’utiliser un LISP qui transpile vers du Javascript plutôt que WASM. Après y’a des trucs qui tentent de le faire, mais ç’a l’air de rester expérimental :
https://github.com/schism-lang/schism
Et sinon y’a ce compilateur Common Lisp qui est intéressant parce qu’il compile vers LLVM et interopère très bien avec C++ (et donc il est en principe possible de génénrer du WASM depuis la sortie LLVM je suppose) :
https://clasp-developers.github.io/
[^] # Re: Et pourquoi pas Web Assembly ?
Posté par jtremesay (site web personnel) . Évalué à 2.
J'aime beaucoup ! Est-ce que tu sais si ça marcherai avec parenscript mentionné par le camarade Leirda< plus bas ? Je trouve leur gestion du dom très élégante !
[^] # Re: Et pourquoi pas Web Assembly ?
Posté par Leirda . Évalué à 1.
Hello!
Alors… Ce que je peux dire avec certitude, c’est que Parenscript et Clasp sont tous deux des compilateurs du même langage : Common Lisp.
Cela signifie que dans une moindre mesure tu devrais pouvoir utiliser l’un ou l’autre des compilateurs sur les mêmes sources et obtenir des binaires qui, exécutés dans leurs environnements respectifs (le navigateur ou un binaire pour ta machine), feront le même travail.
Cependant, tu vas très vite rencontrer des limites à ça car chacun d’entre eux ont leurs spécificités (e.g Parenscript et ses outils de manipulation du DOM, et Clasp avec ses appels natifs vers du C++) qui ne seront pas supportés par les autres compilateurs.
Donc en principe oui, mais en pratique je dirais plutôt non, sauf si tu n’utilises que des fonctionnalités de base, ce qui limite beaucoup l’intérêt.
[^] # Re: Et pourquoi pas Web Assembly ?
Posté par dzecniv . Évalué à 2.
Alors pour Common Lisp + Web Assembly on a un support qui est en train d'apparaître dans l'implémentation ECL (Embedable Common Lisp, qui génère du C): https://gitlab.com/embeddable-common-lisp/ecl/-/merge_requests/277/ Il est évidemment tôt, il faut être motivé pour essayer.
Ce sera sûrement possible dans CLASP en effet, mais j'ai pas entendu que ce soit à l'ordre du jour.
# et parenscript ?
Posté par Leirda . Évalué à 2.
https://parenscript.common-lisp.dev/
Alors c’est plus proche de Common Lisp que d’un Scheme par contre (en fait, c’est littéralement Common Lisp), mais pourquoi pas ?
[^] # Re: et parenscript ?
Posté par jtremesay (site web personnel) . Évalué à 2.
N'ayant aucune connaissance des deux langages, et donc préjugés, et encore peu de code en scheme, si ça marche facilement et avec de bonne perfs, je dis pourquoi pas !
[^] # Re: et parenscript ?
Posté par Leirda . Évalué à 3.
Je pense que c’est une des solutions les plus matures pour le moment.
Common Lisp c’est un standard pour lequel il existe plusieurs compilateurs (SBCL, ECL, Clasp, Parenscript, etc).
Le langage se veut à la fois permettre des abstractions « haut-niveau », mais permet également de mettre les mains dans le cambouis quand c’est nécessaire. Il propose notamment un système d’objet (par prototypes) CLOS (Common Lisp Object System), une gestion d’erreurs très avancée, et l’écosystème est remarquablement mature.
Scheme c’est également un standard (ou plutôt un ensemble de standards à différentes versions : on doit en être à R7RS) pour lequel il existe aussi plusieurs compilateurs (Chez, Chibi, Chicken, MIT Scheme, Guile, etc).
Le langage se veut minimaliste, contrairement à CL. Les standards permettent un peu moins à mon goût de mettre les mains dans le cambouis, mais l’approche fonctionnelle est souvent plus mise en avant. Il ne propose pas de système d’objet par défaut (mais plusieurs bibliothèques existent pour faire ça), mais il propose un système de macros hygiéniques (qui ne brisent pas la frontière entre le code à la compilation et le code à l’exécution), et les SRFI (Scheme Request For Implementation) qui permettent d’étendre amplement ce que l’on peut faire avec le langage.
Je trouve par ailleurs qu’il est plus simple d’utiliser différentes implémentation sur les mêmes sources en Scheme qu’en Common Lisp.
Je dirai qu’une des principales différences entre un Scheme et un Common Lisp, c’est la séparation des espaces de noms entre les fonctions et les variables.
En scheme, il n’y a pas de différence entre
define
une fonction ou une variable :est rigoureusement équivalent à :
Common Lisp, quant à lui, utilise bien deux mots-clés distincts :
n’est pas du tout pareil à :
funcall
nous permet de considérer le contenu d’une variable comme une référence vers une fonction (ou une lambda), et de l’appeler en tant que tel. On n’a pas du tout besoin de cette notion avec un Scheme.[^] # Re: et parenscript ?
Posté par dzecniv . Évalué à 4.
Étonnant ! (généralement c'est le sentiment inverse, l'écosystème des Scheme est très fragmenté, alors que les implémentations de CL partagent un standard).
Franchement je trouve que ce n'est pas important. Et si jamais tu veux vraiment utiliser une variable comme fonction sans utiliser
funcall
, c'est possible:ps: pour les nouvelles et nouveaux venu·es: https://github.com/CodyReichert/awesome-cl
[^] # Re: et parenscript ?
Posté par dzecniv . Évalué à 4. Dernière modification le 06 mars 2023 à 08:57.
oups, du coup dans la première ligne pas la peine du lambda, ça aurait pu être
(defvar add "add (variable)")
.Quand on inspecte un symbole:
on se rend compte qu'il comporte plusieurs "slots", dont un nom, une valeur, une fonction.
Si je prends une fonction au hasard:
le symbole "search" n'a pas de valeur dans l'espace des variables, mais il est lié à une fonction.
[^] # Re: et parenscript ?
Posté par Leirda . Évalué à 1.
Merci pour ces infos !
Je trouve que les espaces de noms variables/fonctions c’est un exemple qui démontre assez bien en quoi Scheme et CL sont différents dans leurs philosophies, mais ça reste anecdotique (et merci pour
symbol-function
!)Je pense que tu as raison, c’est sûrement assez simple de changer de compilo sur CL tant que le standard est respecté, et pour Scheme c’est moins évident et il faut faire attention pour que ça se joue bien…
# Clojurescript
Posté par Papey . Évalué à 4.
Je te suggère d'essayer clojurescript
Au besoin tu peux l'utiliser en conjonction avec Clojure côté serveur.
# let*
Posté par dzecniv . Évalué à 3.
Hello, ça a l'air pas mal LIPS, merci du rappel (sauf le nom, à mon humble avis, trop similaire).
Tu aurais pu utiliser
let*
, à la place des 2let
successifs:=>
(j'ai testé sur la démo que
let*
fonctionne.Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.