Samuel Tardieu @ rfc1149.net

Factor : TD 1

« Paradigmes et langages non classiques 2014

Ce TD permet de manipuler et d’approfondir les différents concepts abordés lors du premier cours sur Factor.

Échauffement

Définir la fonction fact calculant la factorielle d’un nombre. Cette fonction devra retourner 1 pour un paramètre inférieur ou égal à 0. Rappels du cours : on pourra utiliser les mots dup, <= et if. Les blocs de code (similaires à des « lambda » sans arguments) sont délimités par des crochets [ … ]. Les crochets doivent être considérés comme des mots isolés, il faut donc mettre des espaces de manière idoine.

Rappels sur le système de module

Dans Factor, on peut définir les mots qui suivront dans un vocabulaire différent en écrivant :

IN: vocab

Pour utiliser un vocabulaire particulier (et en voir les mots), on peut faire

USE: vocab

ou

USING: vocab1 vocab2 ... vocabN ;

Lorsqu’un mot n’est pas visible mais est connu, l’environnement proposera généralement d’importer automatiquement les différents modules où un tel mot est défini. Il est possible d’encadrer certains mots de <PRIVATE et PRIVATE>. Dans ce cas, ils seront créés dans un vocabulaire dont le nom sera dérivé du nom du vocabulaire courant auquel sera ajouté .private. L’accès depuis le vocabulaire courant est automatique, mais ces mots ne seront pas automatiquement visible depuis d’autres vocabulaires (à moins que le vocabulaire privé soit explicitement utilisé, ce qui est un signe évident de mauvaise pratique en dehors des tests).

Tours de Hanoï

On souhaite faire un programme permettant de résoudre le problème des tours de Hanoï. N tours sont empilées sur le plot 1, et on souhaite les faire arriver sur le plot 3 qui est initialement vide, le plot 2 l’étant aussi. À aucun moment une tour ne peut être placée sur une tour plus petite qu’elle. Pour savoir où créer son premier vocabulaire, voir l’article Creating a vocabulary for your first program dans la documentation de Factor. Le vocabulaire devra se trouver dans la ressource work et s’appeler hanoi.

Affichage d’un mouvement

Faire un mot move ( a b — str ) renvoyant la chaîne de caractères « a vers b ». Par exemple, 1 2 move renverra « 1 vers 2 ». On pourra utiliser string>number pour transformer un entier en chaîne de caractères. On minimisera les répétitions de code en utilisant bi@. On cherchera dans la documentation comment joindre ensemble deux chaînes deux caractères avec un séparateur, les chaînes étant elles-même des tableaux de caractères. Au même endroit que le vocabulaire hanoi, créer un fichier hanoi-tests.factor contenant un ou plusieurs tests unitaires pour la fonction move. On pourra s’inspirer de l’article Testing your first program de la documentation de Factor. Pour tous les mots définis par la suite, on écrira des tests unitaires.

Algorithme

La signature de « hanoi » est :

hanoi ( d a n -- )

d est le plot de départ (entre 1 et 3), a le plot d’arrivée (entre 1 et 3) et n le nombre de tours empilées. Chercher un algorithme récursif permettant de résoudre le problème des tours de Hanoï. On pourra définir les mots suivants si on a besoin :

other ( a b -- o )       ! Étant donnés deux plots a et b, renvoie le 3è
partial ( a b -- a b' )  ! Étant donnés deux plots a et b, renvoie les deux plots a et o
                         ! où o est le résultat de other appliqué sur a et b

Définir le mot principal hanoi avec la signature donnée ci-dessus. De plus, le mot print affiche une chaîne de caractères suivie d’un retour à la ligne. Le mot move défini précédemment sera également utile. Vérifier que le programme fonctionne en appelant

1 3 3 hanoi

Cela doit afficher

1 vers 3
1 vers 2
3 vers 2
1 vers 3
2 vers 1
2 vers 3
1 vers 3

Créer des tests pour le programme hanoi. On pourra utiliser with-string-writer pour rediriger temporairement la sortie par défaut vers une chaîne de caractères.

Refactorisation du code

Éventuellement, refactoriser le vocabulaire en vérifiant à chaque étape que les tests unitaires fonctionnent toujours. Si de nouveaux mots sont créés à cette occasion, il ne faut pas oublier de rajouter de nouveaux tests unitaires. N’oubliez pas qu’il est possible de tester les mots privés. Ne laissez visible que ce qui est nécessaire.

Engrammes

Les engrammes sont un système de numérotation exotique basé sur les facteurs premiers sortis de l’esprit torturé de Natacha Kerensikova. Le but de cette partie du TD est de concevoir un système de codage de nombres classiques sous la forme d’un engramme, puis un système de décodage d’engrammes sous la forme de nombres classiques.

Génération d’engrammes

Écrire un mot >engramme ( n -- str ) qui génère un engramme sous la forme d’une chaîne de caractères. On pourra, pour créer des mots mutuellement récursifs, utiliser la syntaxe DEFER: word qui déclare que le mot word sera défini plus tard dans le vocabulaire. On pourra utiliser le vocabulaire math.primes.factors, et notamment son mot group-factors, pour décomposer un nombre entier en facteurs premiers et leurs puissances associées. Le mot primes-upto pourra également être utile. Rajouter des tests unitaires avec les exemples donnés par Natacha dans la page décrivant les engrammes.

Décodage d’engrammes

On veut écrire un mot engramme> ( str -- n ) qui transforme un engramme codé sous forme de chaîne en nombre classique. Pour cela, on pourra par exemple décoder le chaîne à l’aide d’un mot parse ( str -- engramme ) qui retourne un nombre (0 ou 1) ou un tableau contenant lui-même d’autres nombres ou tableaux. Ensuite, en surchargeant >integer sur les tableaux, on pourra transformer cette structure en nombre. Si un engramme est mal formé, on souhaite générer l’exception malformed. Pour cela, on peut la déclarer à l’aide de ERROR: malformed ;. Cela définit le mot malformed comme levant l’erreur associée (et ne contenant aucun champ).

Mots utiles

On pourra éventuellement avoir besoin des mots suivants pour réaliser ce codage et décodage d’engrammes, ou du vocabulaire peg.ebnf qui permet d’écrire très facilement un parseur :