• Aucun résultat trouvé

Filtrage associatif

Dans le document Réécriture et compilation de confiance (Page 37-40)

2. Le langage Tom 17

2.2. Le cœur du langage

2.2.3. Filtrage associatif

Les constructions de filtrage deTom, débutées par le lexème%match, sont légèrement

différentes des constructionsmatchdes langages fonctionnels commeCaml, car alors que

ceux-ci définissent une valeur comme membre droit, les membres droits des %match

sont des instructions du langage hôte. De manière similaire à l’instructionswitch/case,

lorsqu’un filtre est trouvé, ces instructions sont exécutées, et si le flot de contrôle du

programme n’est pas interrompu, les filtres suivants sont essayés. La définition de la

fonction plus de l’exemple 4 utilise l’instruction Java returnafin d’interrompre le flot

de contrôle lorsqu’un filtre est trouvé.

Si le filtrage n’est pas unitaire — c’est-à-dire qu’il existe plusieurs filtres solutions

du problème de filtrage — alors l’action associée au motif sera exécutée pour chaque

filtre. Le filtrage syntaxique est unitaire, et donc ne permet pas d’expérimenter ce

com-portement. Le langage Tom possède une notion de filtrage de liste, aussi appelé filtrage

associatif avec élément neutre, qui n’est pas unitaire, et permet d’exprimer simplement

des algorithmes manipulant des listes. Les listes sont dans le cas de Tom représentées

par un opérateur algébrique particulier, qui prend un nombre indéfini d’arguments. Si

conc est un tel opérateur définissant une liste d’objets algébriques de sorteNat,conc()

désigne la liste vide d’entiers naturels, tandis que conc(Zero()) dénote une liste à un

seul élément, etconc(Zero(),Zero(),Suc(Zero()))une liste à trois éléments. La liste

vide est considérée comme l’élément neutre des listes, et le système Tom introduit une

distinction syntactique entre les variables de filtrage représentant des éléments, comme la

variablexde l’exemple 4 et les variables représentant une sous-liste d’une liste existante,

qui sont suivies de «*».

Exemple 5. Le filtrage de liste permet d’itérer sur les éléments d’une liste lorsque

l’action associée au motif utilisant ce filtrage de liste n’interrompt pas le flot de contrôle.

Si on considère les listes d’entiers naturels comme des objets algébriques de sorte List

implantées par le type Java ATermList, avec l’opérateur de liste conc, on peut définir

l’affichage de tous les éléments d’une liste par :

public void affiche(ATermList l) {

%match(List l) {

conc(X1*,x,X2*) -> {

System.out.println("En position : " + ‘X1*.length());

System.out.println("Element : "+ ‘x);

}

}

}

L’action associée au motif défini dans cette construction %match est exécutée pour

chaque filtre trouvé, en instanciant les variables de listeX1* etX2*par toutes les

sous-listes préfixes et suffixes de la listel. Notons queX1*correspond à un objetJavade type

ATermList, ce qui permet d’utiliser les fonctions de cette bibliothèque. En particulier,

la méthode length()qui retourne la longueur de la liste est utilisée pour connaître la

position de l’élémentxdans la liste.

Ainsi, cette fonction exécutée sur l’entréel = ‘conc(Zero(), Suc(Zero()), Zero(),

Suc(Suc(Zero())))produit en sortie :

En position : 0

Element : Zero()

En position : 1

Element : Suc(Zero())

En position : 2

Element : Zero()

En position : 3

Element : Suc(Suc(Zero()))

Le langageTom ne spécifie pas l’ordre dans lequel les filtres sont énumérés, mais

énu-mère les filtres un par un, sans se répéter

1

. On voit ici que la listeX1*a été successivement

instanciée par des sous-listes à0,1,2 puis 3éléments.

Cette énumération se fait tant que le flot de contrôle de la construction %match

n’est pas interrompu lors de l’exécution d’une action, à la manière de l’instruction

switch/case qui peut être interrompue par une instruction break ou return

termi-nant l’exécution de la fonction contetermi-nant cette instruction.

Exemple 6. Le filtrage de liste peut être utilisé pour implanter un tri sur les listes par

filtrage de liste conditionnel. Si la même structure de données que dans l’exemple 5 est

utilisée, et que l’on se donne une fonction de comparaison greaterThansur les objets

ATerm, on peut définir ce tri de manière récursive par :

public ATermList bubbleSort(ATermList l) {

conc(X1*,x,y,X2*) -> {

if(greaterThan(‘x,‘y)) {

return ‘bubbleSort(conc(X1*,y,x,X2*));

}

}

_ -> { return l; }

}

1

Certains utilisateurs s’appuyant sur l’ordre d’évaluation actuellement utilisé par le compilateur, il est possible que cet ordre soit spécifié dans une version future

2.2. Le cœur du langage

La règle conditionnelle est exécutée pour tous les filtres, c’est à dire pour tous les couples

d’élémentsx,ydans la liste argument, avecX1*etX2*les variables de listes capturant les

contextes dans la liste. Le test if(greaterThan(‘x,‘y)), qui est une instruction Java,

est exécuté pour chacun de ces couples ; lorsque la fonction trouve un couple tel que x

est plus grand que y, alors ces deux éléments sont échangés et la fonction est rappelée

récursivement sur le résultat.

S’il n’existe pas de tel couple, alors tous les filtres pour le premier motif sont éliminés,

et la règle suivante est essayée, car il n’y a pas d’interruption du flot de contrôle du

programme. Cette seconde règle, utilisant la notation _, filtre pour toute entrée, et la

liste originale est retournée, correspondant au cas de base de la définition récursive car

il n’existe pas de couplex,y avec x plus grand quey, et donc la liste est triée.

Les constructions de filtrage deTomoffrent de plus la possibilité d’exprimer des motifs

non-linéaires. Ainsi, lorsqu’un même nom de variable apparaît plusieurs fois dans un

motif, il est nécessaire pour obtenir un filtre que les sous-termes correspondant aux

instances de ces variables soient égaux. Cela est particulièrement utile combiné avec le

filtrage de liste, pour exprimer la recherche et l’élimination des doublons dans une liste,

ou pour vérifier la présence d’un élément donné dans une liste.

Exemple 7. En utilisant la définition de structure de données de l’exemple 5, on peut

définir une fonction éliminant les doublons dans une liste par filtrage de liste non-linéaire,

sur le modèle de l’algorithme de tri de l’exemple 6 :

public ATermList removeDouble(ATermList l) {

%match(List l) {

conc(X1*,x,X2*,x,X3*) -> {

return ‘removeDouble(conc(X1*,x,X2*,X3*));

}

}

return l;

}

Exemple 8. On peut aussi utiliser la non-linéarité lorsque la construction de filtrage a

plusieurs sujets (comme celle qui définit la fonctionplusde l’exemple 4), pour retrouver

des sous-termes partagés par ces sujets. On peut ainsi définir la recherche d’un élémente

dans une listel, en utilisant toujours la structure de données de l’exemple 5, retournant

true si l’élément est présent dans la liste, etfalse sinon :

public boolean search(ATerm e, ATermList l) {

%match(Nat e, List l) {

x, conc(_*,x,_*) -> {

return true;

}

}

return false;

}

La notation_* dans cet exemple indique une variable de liste non nommée. On ne peut

alors pas utiliser sa valeur dans le membre droit de la règle. Les deux occurrences de_*

désignent des variables non-nommées différentes, ce qui fait que le second motif itère sur

les éléments de la listel. L’action associée n’est cependant exécutée que lorsque le motif

entier filtre, c’est à dire lorsque l’élémentx, ayant pour valeurepar filtrage est retrouvé

dans la listel.

Dans le document Réécriture et compilation de confiance (Page 37-40)