A la découverte de Factor
Factor est un langage assez récent (il fête en 2009 sa sixième année de développement), néanmoins les concepts qu'il embarque ne le sont pas tant que cela, puisque c'est un héritier de Forth, le célèbre langage à pile (je dis célèbre, mais peut-être que PostScript le sera plus pour certains d'entre vous). Il a été développé par Slava Petrov, auteur du fameux éditeur de texte JEdit.
La page d'acceuil de Factor en dit peu sur le langage : innovatif, expressif et rapide sont les divers qualificatifs qui lui sont attribués, et nous allons tâcher ici de comprendre en quoi.
Je ne détaillerai pas ici l'installation de Factor, celle-ci se faisant toute seule à partir de la page d'acceuil.
Autre point, pour ce tutoriel uniquement, il ne sera pas nécessaire d'utiliser un quelconque éditeur de texte pour vos scripts, puisque nous allons travailler uniquement avec le listener (la console fournie d'office avec Factor).
Petits rappels
Le temps où vous faisiez des maths est peut-être lointain, néanmoins nous allons rapeller ici certains concepts sur les notations mathématiques. Et rassurez-vous, on n'ira pas plus loin que l'addition en étudiant "2+3" !
Infix
C'est celle que nous utilisons tous les jours. Le IN de Infix signifie "à l'intérieur" ou "dedans". Mais à l'intérieur de quoi me direz-vous ? On parle en fait ici de l'opérateur (ici le "+") que vous utilisez, et il doit se placer à l'intérieur des opérandes (ici les nombres).
2 + 3 Prefix
PRE signifie "avant", ainsi l'opérateur s'écrit avant les opérandes. Les langages Lisp et Scheme l'utilisent.
+ 2 3 Postfix
POST signifie "après", et si vous avez bien suivi jusqu'à maintenant, vous écrirez les yeux fermés:
2 3 +
Si vous n'êtes pas tout jeune, vous avez peut-être déjà utilisé cette notation (dite "polonaise inversée") lorsque vous planchiez sur un DS de maths au lycée avec une calculatrice HP.
C'est cette syntaxe qui sera utilisée par la suite avec Factor.
Chacune des ces notations possède ses avantages et inconvénients. Avec la notation infixée, on doit connaître au préalable les priorités ou bien placer correctement des parenthèses. En notation postfixée, le fait que la multiplication soit traitée en premier devient implicite. Enfin, en préfixée, la multiplication est encore implicite mais devient vite complexe à lire lorsque l'on commence à imbriquer les opérations. Notez toutefois que la notation traditionnelle en mathématiques les utilise toutes les trois, et c'est bien là le noeud du problème lorsqu'il s'agit de parser de telles expressions.
Par ex. 2+3
est la notation infixée, sin
est une notation préfixée, la dérivation f'
pour une fonction f dérivable sur un domaine donné est une notation postfixée.
,Mais que peut-on donc faire avec une pile ?
Le concept de "pile" en informatique est loin d'être nouveau. Pensez par exemple à la pile d'assiettes que vous avez encore en ce moment même sur votre évier!
C'est une structure de données dite "dernier entré, premier sorti" dans laquelle on peut ajouter un élément avec l'instruction push
ou bien en retirer un avec pop
.
Voici un magnifique schéma ASCII pour illustrer mes propos. Supposons que notre pile possède les éléments a,b et c (c étant le dernier entré) et que nous voulions lui ajouter un élément d. On utilisera pour cela l'instruction push
ainsi: "d push" (et non "push d", rapellez-vous la notation postfixée!) :
| | | d | | c | | c | | b | --------> | b | | a | d push | a | |___| |___|
Maintenant, on va retirer le dernier élément de la pile avec pop
:
| d | | | | c | | c | | b | --------> | b | | a | pop | a | |___| |___|
Bien sûr, pour le moment a,b,c et d ne représentent que des entités imaginaires, et comme dit la pub:
C'est à vous d'inventer la vie qui va avec!
,Comment Factor utilise la pile ?
En fait, seules deux possibilités s'offrent à vous (en réalité, c'est un poil plus complexe que cela) :
- Soit vous entrez un élément sur la pile;
- Soit vous appelez un
mot
(tout simplement une fonction) qui va alors consummer des éléments de la pile.
Etudions ensemble un petit exemple avec le listener de Factor. C'est le traditionnel "Hello world!" :
(scratchpad) "Hello world!" print Hello world!
Tout d'abord, on pousse l'élément "Hello world!" sur la pile, puis le mot print
. Lorsque Factor rencontre un mot
sur la pile, il éxécute celui-ci.
Afin de comprendre comment fonctionnent ces mots, nous allons utiliser la documentation fournie avec Factor. Pour cela, appuyez sur le bouton Search
du listener. Dans la zone de recherche, entrez "print" puis cliquez sur la ligne "print ( string — )".
Nous sommes alors redirigés vers la documentation de print
et la première ligne est:
print ( string -- )
Ceci signifie que print
prend un seul argument en entrée (ce qui se trouve devant le symbole "—"), de type string
, et que le mot ne renvoie rien (ce qui se trouve derrière le symbole "—" ).
La doc nous renseigne aussi sur le vocabulaire
auquel appartient ce mot, et sur le rôle de celui-ci: ici, on imprime une chaîne à l'écran suivi d'une nouvelle ligne.
Pour voir le processus d'encore plus près, on peut entrer les instructions les unes après les autres dans la pile:
(scratchpad) "Hello world!" --- Data stack: "Hello world!" (scratchpad) print Hello world!
On peut déjà appliquer ce principe à de petits calculs arithmétique simples:
(scratchpad) 2 3 --- Data stack: 2 3
Remarquez que la pile est affichée la tête en bas dans le listener, et ainsi le nombre "2" est en fait en bas de la pile.
Si on désire ajouter ces deux nombres, on va utiliser le mot +
:
(scratchpad) + --- Data stack: 5 ,Quelques mots supplémentaires
Il y a de grandes chances que votre pile devienne un amas de données immaintenable si vous continuez à amasser des éléments à l'intérieur.
Voici quelques mots élémentaires pour vous aider dans son maniement:
drop ( x -- )
: enlève le dernier élément de la pile et le jette;. ( obj -- )
: affiche le dernier élément de la pile;clear ( -- )
: vide la pile;
Exemples
(scratchpad) 2 3 - --- Data stack: -1 (scratchpad) drop (scratchpad) 20 5 / . 4 (scratchpad) 2 3 + 6 7 --- Data stack: 5 6 7 (scratchpad) clear (scratchpad) ,Nos premiers mots
Commençons par écrire un mot
tout simple qui nous permettra de doubler l'argument qui lui est donné en entrée:
( scratchpad ) : double-du-nombre ( nombre -- sondouble ) 2 * ; ( scratchpad ) 5 double-du-nombre . 10 La syntaxe
Reprenons la définition de notre mot :
: double-du-nombre ( nombre -- sondouble ) 2 * ;
- Deux points
:
sont utilisés pour commencer la définition d'un mot. - Vient ensuite le nom que l'on va donner à notre mot, ici
double-du-nombre
. Comme vous pouvez le constater, Factor vous permet beaucoup de liberté quant au nommage de ceux-ci, et beaucoup de caractères spéciaux et interdits dans les définitions de fonctions dans d'autres langages sont ici permis. Si vous avez déjà pratiqué Lisp ou un de ses dialectes, vous ne serez pas surpris cependant. Sachez enfin qu'il existe des conventions de nommage, par ex. un mot qui renverra un booléen (soit vrai, soit faux) se terminera par le point d'interrogation?
: est-pair? voyelle? etc. - La partie entre parenthèses
( nombre -- sondouble )
est ce que l'on apelle la déclaration d'effet de pile
(stack effect en Anglais). On la nomme aussi signature en langage informatique. Celle-ci est formée de deux parties, séparées par le double signe moins--
. Chacune d'elle est une liste d'arguments séparés par un espace.- celle de gauche représente la liste des éléments de la pile qui seront consommés par notre mot.
- celle de droite est la liste des entités qui y seront pousseés.
Tous les mots que vous definirez devront renseigner cet
effet de pile
, à moins qu'ils n'accumulent des valeurs sur celle-ci. Le nom que vous donnerez à ces arguments n'a que peu d'importance,( elt elt -- seq )
ou( x y -- z )
représente le même effet, mais la première syntaxe est tout de même plus explicite.Enfin, et c'est certainement là où j'avoue me prendre les pieds dans le tapis le plus souvent, ces argument ne sont pas utilisés à l'intérieur du corps de votre mot. Ainsi, notre mot précédent ne pourrait pas s'écrire ainsi :
: double-du-nombre ( nombre -- sondouble ) nombre 2 * ;
Vous obtiendriez alors l'erreur suivante:
Word not found in current vocabulary search path "name" "nombre"
vous précisant que le mot n'est pas défini!
- Suit la définition du mot proprement dit; comme nous venons de le voir, il est implicite que les arguments donnés sont déjà sur la pile.
- Et enfin toute défintion d'un mot doit se terminer par un espace suivi d'un point-virgule
;
.
Avec Factor, toutes les instructions doivent être séparées par des espaces, car tout est un mot
. Les point-virgule, deux-points, les parenthèses, etc. sont en fait des mots placés ensemble pour former la syntaxe du langage! En cela, le concept "code is data" tant vanté par les programmeurs des dialectes de Lisp est aussi vrai avec Factor. ( et les macros ? Oui, elles sont là aussi! )
Ajouter un commentaire