Sème

un langage pour jouer avec l'algorithmique

a marqué ce sujet comme résolu.

Bonjour !

Allez, je me lance. Vu que j’y ai été invité par Situphen, je vous présente mon petit projet du moment. Le soleil brille, la petite a trouvé tous ses œufs, le moment est idéal.

D’abord une petite parenthèse pour préciser que si j’ai choisi "Sème" comme pseudo, ce n’est pas parce que je suis un morphal qui ne veut que présenter son projet. Mon pseudo habituel, c’est "Zéro", et c’est le nom sous lequel je me suis inscrit. Puis en surfant un peu, j’ai fini par comprendre que ZdS était un descendant du SdZ. Du coup, il me semblait inapproprié de garder ce pseudo "Zéro". Comme "Sème" est mon mot du mois, j’ai pris ça. C’est le nom "Sème" d’où découle "sémantique". Bref, on s’en fiche.

Alors c’est quoi-t-y ce projet. D’abord, je m’adresse aux développeurs : non, ce n’est pas un langage de programmation nouveau et génial, que vous pourriez utiliser pour faire des trucs somptueux ou inédits. Maintenant je m’adresse aux noobz : oui, c’est un petit langage de programmation, mais si vous souhaitez devenir développeur de logiciels, commencez plutôt par un vrai langage, Python, C++, Java, Perl, ce que vous voulez. Si vous voulez faire carrière, ce n’est pas une bonne idée de commencer par Sème, parce que ce langage ne vous préparera pas à une quelconque activité professionnelle.

Ok, du coup à qui ça s’adresse ? Eh bien il y a des gens qui apprécient le sudoku, les mots croisés, les jeux de société en général, les puzzles et les casse-têtes chinois, les échecs et le jeu de go. Je pense que ça s’adresse plutôt à eux. J’ai plutôt envie de décrire Sème comme une plateforme permettant à ses utilisateurs de "jouer" avec l’algorithmique. C’est très basé sur "Computer Science Logo Style" de Brian Harvey, dont je suis un gros fan. C’est un livre énorme (j’adore les livres énormes, voyez-le comme le Seigneur des Anneaux des bouquins sur la programmation), dont la progression est lente, agréable, presque (za)zen. Sème, c’est un jeu pour les gens calmes.

Techniquement, c’est un croisement de Logo, le langage qui se cache derrière la célèbre tortue, et de Io, le langage (trop) moderne de Steve Dekorte. Une des caractéristiques de Sème est de ne pas avoir de forme spéciale (dans un langage classique x=x+1 est une forme spéciale, puisque le 1er x n’est pas remplacé par sa valeur).

1
2
make: 'x 5
print: x

Ce petit bout de code affecte 5 à la variable nommée "x", puis affiche la valeur de la variable x. Le x de la 1ère ligne est précédé d’une apostrophe : cela indique à l’interpréteur qu’on ne parle pas du contenu de x mais du symbole "x". En anglais, apostrophe se dit "quote", et "quote" veut aussi dire "citer". Ici, on "cite" le nom "x".

Mettre deux points à la fin d’un mot indique à l’interpréteur qu’on souhaite appeler la fonction. Dans notre exemple, on appelle la fonction "make", et on appelle ensuite la fonction "print".

L’interpréteur vous donne les arguments de fonction dans l’ordre où ils arrivent, dans le plus pur style Logo : si la fonction a besoin de trois arguments, les trois tokens suivant la fonction seront pris comme arguments. Dis autrement, c’est de la notation polonaise, dite "préfixée" :

1
+ 5 * 3 6

Ceci signifie "la somme de cinq et du produit de 3 par 6".

Toutes les valeurs sont des objets (littéralement), et tous les objets ont des attributs. Un attribut est comme une variable interne, contenue dans l’objet. Imaginons qu’on souhaite représenter un chien. Il pourrait avoir un attribut nom, un attribut race, taille, âge, …etc. Voilà à quoi cela ressemblerait.

1
2
3
4
new: 'Maxou [ Chien ]
Maxou'set: 'âge 4
Maxou'set: 'race 'Charclo
Maxou'set: 'taille 40

La 1ère ligne crée un objet "Maxou" ayant "Chien" comme prototype, mais on en reparlera plus tard.

Ce que je veux mettre en valeur ici, c’est qu’on vient de définir plusieurs attributs de Maxou, mais que certains de ces attributs mériteraient des précisions. Notamment, on aimerait pouvoir préciser l’unité de mesure de la taille, ainsi qu’une marge d’erreur pour l’âge parce qu’en fait on n’a jamais su exactement l’âge qu’il avait, ce chien. Ben oui, il s’est donné. Fastoche, on peut donner des attributs aux attributs :

1
2
Maxou'âge'set: 'margeErreur 1.5
Maxou'taille'set: 'unitéMesure 'cm

Voilà, ce n’est pas compliqué. Bon je sais je vous le fais un peu au lance-pierre, et j’en suis désolé, mais il faut bien commencer quelque part. Je suis preneur de questions, et avide d’y répondre.

Je vais détailler un peu la syntaxe. Une apostrophe qui précède un nom indique qu’on parle du nom lui-même et non de ce qu’il symbolise, comme on l’a vu. Maintenant le nouveau truc : une apostrophe qui suit un nom indique à l’interpréteur qu’il doit ramener l’attribut qu’on va identifier juste après :

1
Maxou' 'âge

En écrivant ceci, on dit à l’interpréteur "l’attribut âge de l’objet Maxou". Comme ça passait bien, j’ai mis un peu de sucre syntactique comme on dit, et dans ce genre de situations on peut écrire directement :

1
Maxou'âge

Ce qui veut dire la même chose.

Maintenant, que se passe-t-il si je demande à un objet un attribut qu’il ne possède pas ? Vous me voyez venir :

1
Maxou'aboie: 'wafwaf

Si l’attribut ne peut être trouvé dans l’objet lui-même, il sera recherché dans ses prototypes (en depth-first). Maxou n’a pas d’attribut "aboie", mais si l’objet "Chien" en a un, c’est cet attribut qui sera utilisé. On fait donc de l’héritage multiple à la "Io".

Allez, un dernier petit mot sur les fonctions. On n’a pas de type "fonction" en Sème. On écrit juste un bloc entre crochets, et on lui colle un attribut "input" contenant la liste des noms de paramètres attendus :

1
2
3
4
5
6
7
8
9
make: 'fib [
    ife: < num 3
        [ 1 ]
        [ +
            fib: - num 1
            fib: - num 2
        ]
]
fib'set: 'input [ num ]

Tout ça reste très primitif bien sûr, j’en suis au tout début. Les choses peuvent bouger encore beaucoup. Mais ma petite Fibonacci récursive fonctionne, sur une implémentation en JS pur dans le browser, avec une jolie interface épurée. C’est ultra lent : 6 secondes pour fib(20). Mais bon, je n’ai pas l’objectif d’en faire quelque chose de rapide de toute façon. Pourquoi ? Je répondrais : pourquoi pas ?

Voilà un peu ce que je fais en ce moment. J’espère apprendre à vous connaitre, m’intégrer peut-être petit à petit dans cette communauté qui est la vôtre, et qui m’a l’air sympa.

Bon weekend de Pâques !

Salut,

Je trouve que c’est un projet intéressant. Par contre, je ne suis pas vraiment satisfait par ton approche de construction impérative des valeurs (et fonctions). Deux façons de voir les choses:

  • J’aime l’idée que dans un programme il y a des valeurs qui ont du sens, et qu’on peut les manipuler directement (les construire et les déconstruire). Une fonction ça a du code et des paramètres, c’est ça qui la décrit, et j’ai envie de pouvoir décrire cela, d’un seul tenant, dans mon langage, au lieu d’être forcé de définir d’abord l’un puis l’autre. Pareil, si un Chien est censé avoir un age et une râce, j’ai envie de pouvoir définir ça en même temps que son nom, ça forme un tout. (Le nom, l’age et la race, tout ensemble, c’est ça un chien.)

  • Un objet respecte certains invariants, et normalement les états intermédiaires qui ne respectent pas les invariants ne sont pas observables à l’extérieur. En faisant ta construction pas à pas, tu laisses la main au programmeur dans des états où les objets n’ont pas de sens – ne respectent pas leurs invariants. Par exemple si j’ajoute du code après make: 'fib ... mais avant fib'set: ..., je peux observer un monde où 'fib est un bloc de code sans paramètre (mais qui ne peut pas être exécuté correctement), les invariants sont cassés.

J’aurais tendance à penser que dans un programme, il n’y a pas que du code et des messages, il y a aussi des données, et qu’un langage devrait me permettre de les manipuler d’une façon qui respecte leur sens. Par exemple en Smalltalk on peut écrire:

1
(BLabel new: statsWindow label: 'Score') x: 0 y: 0 width: 100 height: 16.

et la partie x: 0 y: 0 width: 100 height: 16 c’est une donnée qui est décrite d’un seul morceau.

+0 -0

Salut, merci pour le retour. Je suis plutôt d’accord avec ton analyse, ça me gêne aussi de devoir construire pas à pas les choses.

Par rapport aux fonctions, je voulais de toute façon faire une fonction "fun" ou "function", qui prendrait en entrée le nom de la future fonction, un bloc contenant les noms des paramètres, et un bloc contenant le corps. En arrière-plan, cette fonction construirait un bloc et lui affecterait un attribut "input". Du coup le débutant, à qui on présente cette façon de faire en premier, n’a pas accès à cette twilight zone entre le make: fib et le fib'set:.

C’est un peu le cas du make, d’ailleurs. J’ai commencé par faire une fonction "new" qui ne crée un objet que s’il n’existe pas déjà, et une fonction "set" qui n’affecte une valeur que si l’objet existe. Après j’ai fait le make en combinant les deux.

L’autre gros manque, finalement, c’est l’absence de notation littérale pour les objets. Un peu comme JSON quoi. Alors je marche encore sur des œufs. Si tu as remarqué, je n’utilise même pas le terme de "liste" pour parler de ce qu’il y a entre crochets. Dans Logo par exemple, c’est clairement des listes (c’est sa filiation Lisp). Mais là même pas.

J’appelle le langage "Sème", donc c’est bien que la sémantique me turlupine. Mais d’un autre côté, j’ai envie de dire qu’un bloc, un datum, ne prend de sens que dans la façon dont on l’utilise. Par exemple pour les fonctions, ça n’a le sens de fonction que quand on décide de l’appeler, ou de le traiter comme une fonction (dans une higher order par exemple). Qu’en penses-tu ? Le cendrier que j’ai devant moi, ce n’est qu’un bout de pierre taillée. Il prend le sens de cendrier parce que je sais que c’est à cela qu’il sert, et surtout parce que c’est comme cela que je m’en sers…

J’ai pensé à une notation. Cela donnerait :

1
2
3
4
5
6
7
8
9
seta: 'Maxou {
    nom = 'Maxou {}
    âge = 4 {
        margeErreur = 1.5 {}
    }
    taille = 40 {
        unitéMesure = 'cm {}
    }
}

Mais je trouve cela un peu lourd. Tout ça me fait bien cogiter. :)

Mais d’un autre côté, j’ai envie de dire qu’un bloc, un datum, ne prend de sens que dans la façon dont on l’utilise. Par exemple pour les fonctions, ça n’a le sens de fonction que quand on décide de l’appeler, ou de le traiter comme une fonction (dans une higher order par exemple). Qu’en penses-tu ? Le cendrier que j’ai devant moi, ce n’est qu’un bout de pierre taillée. Il prend le sens de cendrier parce que je sais que c’est à cela qu’il sert, et surtout parce que c’est comme cela que je m’en sers…

Il y a deux points de vue duaux. On peut voir les données à travers les calculs qui les manipulent, et on peut voir les calculs à travers les données qu’ils manipulent. Un plateau du jeu d’échec prend du sens à travers l’ensemble des coups qu’il rend possible pour le prochain joueur, et des parties qui s’ensuivent (données vues à travers des calculs); mais on peut définir le sens d’un coup d’échec comme un passage d’un plateau à un autre plateau (calcul vus à travers des données).

Personellement je pense qu’un langage de programmation doit permettre les deux points de vue, puisqu’ils sont aussi riches et intéressants l’un que l’autre. On peut faire du réductionnisme dans un sens comme dans l’autre (voir le code seulement comme des données, en abusant la philosophie Lisp; voir les données seulement comme des objets, en abusant la philosophie Smalltalk), mais c’est une forme de réductionnisme qui rend un système plus petit sans le rendre plus simple.

+0 -0

Merci, c’est super intéressant.

Je me suis renseigné sur la notion d’invariant que tu avais utilisée, et que je ne connaissais pas. C’est une chose dont on peut considérer qu’elle est vraie (on peut lui faire confiance). Je vois tout à fait le problème, d’un espace dans le code où les choses ne sont pas complètement définies, comme une moitié de fonction, à qui il manquerait un organe primordial non encore formé : le nom de ses paramètres.

C’est vrai que je suis parti complètement en mode "pâte à modeler". On balance de jets de peinture dans l’espace, ça finit par faire des formes reconnaissables (comme des fonctions par exemple). C’est peut-être un langage impressionniste ?

Tu me dis si je me trompe, mais il me semble que la phrase importante, dans ton propos, c’est : "dans un programme, il n’y a pas que du code et des messages, il y a aussi des données, et un langage devrait me permettre de les manipuler d’une façon qui respecte leur sens".

En utilisant make on crée des variables héritant de l’objet Object, qui définit tout un tas de méthodes dont set par exemple. Mais la fonction new permet de préciser explicitement les parents de l’objet créé. Donc imaginons qu’on travaille avec des formes géométriques, genre triangle rectangle et compagnie, on peut faire en sorte de n’avoir à disposition que des fonctions faites pour traiter des triangles rectangles, des triangles, et des polygones, par héritage. Est-ce que cela permet, à tes yeux, de récupérer cette notion de "manipuler les données d’une façon qui respecte leur sens" ?

Edit : En fait, tu es vraiment en train de me bousculer, là, c’est génial. Il y a un truc pas clair dans ma conception, faut que je bosse là-dessus. Dans l’état actuel, je ne peux tout simplement pas avoir de fonction anonyme ! J’aime autant te dire que ça me plait moyen. Allez. Hop, au boulot.

+0 -0

Hello,

Depuis tout ce temps, j’ai pas mal travaillé sur Sème. Le noyau a été refait à neuf, j’ai commencé à implémenter une partie des 300 brouettes de fonctions Logo, je corrige des petits bugs à droite à gauche bien sûr…

Hier et aujourd’hui, j’ai mis en place le nouveau site Le langage Sème

Attention, peinture fraîche ! :D Alors qu’en pensez-vous ?

Merci Koladz, ça fait plaisir. Pour la faq, je n’ai pas encore eu le temps de la mettre en place, et ce que tu as lu c’est la faq d’origine livrée avec le CMS. Je pense expliquer comment utiliser le langage petit à petit, en écrivant des billets de temps en temps, tout en mettant une compilation des billets en format PDF disponible sur le site. C’est en fait la raison d’être de Sème : me permettre de créer des petits projets, d’expliquer pas à pas les choses, en faisant (humblement) pour Sème ce que Brian Harvey a fait pour Logo avec son livre "Computer Science Logo Style". C’est l’idée en tout cas. Mais il se peut aussi que je me lasse.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte