550 likes | 637 Views
Techniques de R éé criture et Transformations. Pierre-Etienne Moreau. Manipulation de listes. Repr é sentation des listes. Habituellement, on consid è re une liste vide nil , et un op é rateur de concat é nation cons nil : L cons : E x L L
E N D
Techniques de Réécriture et Transformations Pierre-Etienne Moreau
Représentation des listes • Habituellement, on considère une liste vide nil, et un opérateur de concaténation cons nil : L cons : E x L L On représente ainsi la liste a.b.c par cons(a,cons(b,cons(c,nil)))
Question • Comment retrouver un élément donné ? appartient(cons(a,cons(b,cons(c,nil))),a) ? appartient(cons(a,cons(b,cons(c,nil))),b) ? appartient(cons(a,cons(b,cons(c,nil))),d) ?
Une réponse appartient(cons(x,l),x) true appartient(cons(y,l),x) appartient(l,x) appartient(nil,x) false
Une autre réponse • Dans Tom on peut écrire appartient( (_*,x,_*) , x) true appartient( l , x) false
Symboles associatifs • f est associatif si : f(x,f(y,z)) = f(f(x,y),z) • Dans ce cas, a-t-on : • f(a,f(b,f(c,d))) = f(f(a,b),f(c,d)) ? • tel que f(x,f(c,y)) = f(f(a,b),f(c,d)) ? • f(x,f(c,y)) << f(f(a,b),f(c,d)) ? • f(x,f(c,y)) << f(a,f(b,f(c,d))) ? • f(x,f(d,y)) << f(a,f(b,f(c,d))) ?
Associativité avec élément neutre • f(x,f(y,z)) = f(f(x,y),z) • f(x,e) = f(e,x) = x • Dans ce cas, a-t-on : • f(x,f(c,y)) << f(a,f(b,f(c,d))) ? • f(x,f(d,y)) << f(a,f(b,f(c,d))) ?
Associativité dans Tom • On considère les formes aplaties : • f(a,b,c,d) • f(x,c,y) • On peut écrire : • f(x,c,y) << f(a,b,c,d) • f(x,d,y) << f(a,b,c,d)
Questions • Comment savoir s’il y a un ‘a’ suivi d’un ‘b’ ? • f(x,a,y,b,z) << f(a,b,c,d) • Avec exactement un terme entre les deux ? • On ne peut pas l’exprimer
Signature • f est d’arité variable et a pour profil : • f : E x … x E -> L • On le note : • f( E* ) -> L • Cela permet d’écrire : • f(a(),b(),c(),d()) • f(x,a(),y,b(),z)
Questions • Quel est le type de x,y et z dans f(x,a(),y,b(),z) ? • réponse : E • Comment exprimer f(x,c(),y) tel que cela filtre vers f(a(),b(),c(),d()) ? • Il faut des variables de type L • On les note f(x*,c(),y*)
Exercice • Exprimer la fonction d’appartenance sur des listes associatives appatient(f(_*,x,_*),x) -> True appatient(f(_*),x) -> False
Exercice • Comment éliminer les doublons ? • f(X*,e,e,Z*) -> f(X*,e,Z*) • élimine les doublons consécutifs • Comment éliminer les doublons distants • f(X*,e,Y*,e,Z*) -> f(X*,e,Y*,Z*)
Exercice • Etant donné un ordre sur les éléments • Exprimer un algorithme de tri • f(X*,e1,e2,Y*) -> f(X*,e2,e1,Y*) if e2<e1 • Implanter le en Tom
Implantation d’un algorithme de filtrage syntaxique • Utiliser des symboles associatifs • Quelle signature choisir ? Variable(name:String) -> Term Appl(name:String, args:TermList) -> Term conc( Term* ) -> TermList True -> Term False -> Term Match(pattern:Term, subject:Term) -> Term And( l:TermList ) -> Term
Codage des règles et des termes %rule { // PropagateClash And(conc(_*,False(),_*)) -> False() // PropagateSuccess And(conc(X*,True(),Y*)) -> And(conc(X*,Y*)) And(conc(X*,True(),Y*)) -> And(conc(X*,Y*)) And(conc(X*,c,Y*,c,Z*)) -> And(conc(X*,c,Y*,Z*)) And(conc()) -> True() } Term p2 = `Appl("f",conc(Variable("x"),Appl("g",conc(Variable("y"))))); Term s2 = `Appl("f",conc(Appl("a",conc()),Appl("g",conc(Appl("b",conc())))));
Programmation par réécriture • Avantages • le filtrage est un mécanisme expressif • les règles expriment des transformations élémentaires • Limitations • les systèmes de règles sont souvent non-terminant et/ou non confluent • en général, on ne veut pas appliquer toutes les règles en même temps
Exemple de système non terminant And(Or(x,y),z) Or(And(x,z),And(y,z)) And(z,Or(x,y)) Or(And(z,x),And(z,y)) Or(And(x,y),z) And(Or(x,z),Or(y,z)) Or(z,And(x,y)) And(Or(z,x),Or(z,y)) Not(Not(x)) x Not(And(x,y)) Or(Not(x),Not(y)) Not(Or(x,y)) And(Not(x),Not(y)) And(Or(a,b),c) Or(And(a,c),And(b,c)) And(Or(a, And(b,c)),Or(c, And(b,c))) …
Codage du contrôle dans les règles • Solution classique • introduire un nouvel opérateur f pour restreindre l’ensemble de règles permettant de normaliser • l r devient f(l) r’ • on normalise un terme f(t) • l’opérateur f permet de contrôler les règles à appliquer
Encodage du contrôle f(And(x,y)) and(x,y) f(Not(x)) not(x) f(Or(x,y)) Or(f(x),f(y)) and(Or(x,y),z) Or(and(x,z),and(y,z)) and(z,Or(x,y)) Or(and(z,x),and(z,y)) and(x,y) And(x,y) not(Not(x)) x not(And(x,y)) Or(not(x),not(y)) not(Or(x,y)) and(not(x),not(y)) not(x) Not(x) f(And(Or(a,b),c)) and(Or(a,b),c)) Or(and(a,c),and(b,c)) Or(And(a,c),And(b,c))
Conséquences • Il faut définir la congruence explicitement, pour chaque règle et chaque constructeur • Il n’y a plus de séparation entre transformation et contrôle • cela rend la compréhension plus difficile • les règles sont moins réutilisables
Ce qu’on voudrait • pouvoir contrôler l’application des règles • pouvoir spécifier simplement la « traversée » d’un terme (i.e. appliquer une règles dans les sous-termes) • tout en séparant règle et contrôle
Solution • Utiliser des stratégies • Combiner des transformations élémentaires • Exemples • disjunctive normal form dnf = innermost(DAOL <+ DAOR <+ DN <+…) DAOL : And(Or(x,y),z) Or(And(x,z),And(y,z)) DAOR : And(z,Or(x,y)) Or(And(z,x),And(z,y)) DN : Not(Not(x)) x • conjunctive normal form cnf = innermost(DOAL <+ DOAR <+ DN <+…)
Règle de réécriture • Une règle R : g d est une stratégie élémentaire • Exemples : R = a b • (R)[a] = b • (R)[b] = fail • (R)[f(a)] = fail
Identité et échec • id : ne fait rien, mais n’échoue pas • fail : échoue tout le temps • Exemples • (id)[a] = a • (id)[b] = b • (fail)[a] = fail
Composition • S1 ; S2 • Applique S1, puis S2 • Echoue si S1 ou S2 échoue • Exemples • (a b ; b c)[a] = c • (a b ; c d)[a] = fail • (b c ; a b)[a] = fail
Choix • S1 <+ S2 • Applique S1. Si cela échoue, applique S2 • Exemples • (a b <+ b c)[a] = b • (b c <+ a b)[a] = b • (b c <+ c d)[a] = fail • (b c <+ id)[a] = a
Quelques lois • id ; s = s • s ; id = s • id <+ s = s • s <+ id ≠s • fail <+ s = s • s <+ fail = s • fail ; s = fail • s ; fail ≠fail (pourquoi ?)
Stratégies paramétrées • try(s) = s <+ id • repeat(s) = try(s ; repeat(s)) • Exemples • (try(b c))[a] = a • (repeat(a b))[a] = b • (repeat(b c <+ a b))[a] = c • (repeat(b c))[a] = a
Primitives pour traverser • applique une stratégie à un ou plusieurs fils directes • Congruence • applique une stratégie différente à chaque fils d’un constructeur • all • applique une stratégie à tous les fils • one • applique une stratégie à un fils
Congruence • c(S1,…,Sn) pour chaque constructeur c • Exemples • (f(a b))[a] = fail • (f(a b))[f(a)] = f(b) • (f(a b))[f(b)] = fail • (g(try(b c) <+ try(a b)))[g(a,a)] = g(a,b) • Exercice • définir la stratégie map sur les liste (cons,nil)
Congruence générique • all(S), échoue si S échoue sur un des fils • Exemples • (all(a b))[f(a)] = f(b) • (all(a b))[g(a,a)] = g(b,b) • (all(a b))[g(a,b)] = fail • (all(a b))[a] = a • (all(try(a b)))[g(a,c)] = g(b,c)
Congruence générique • one(S), échoue si S ne peut pas s’appliquer sur un des fils • Exemples • (one(a b))[f(a)] = f(b) • (one(a b))[g(a,a)] = g(a,b) • (one(a b))[g(b,a)] = g(b,b) • (one(a b))[a] = fail
Stratégies de parcours • bottomup(S) = all(bottomup(S)) ; S • topdown(S) = S ; all(topdown(S)) • innermost(S) = bottomup(try(S ; innermost(S))) • oncebu(S) = one(oncebu(S)) <+ S • oncetd(S) = S <+ one(oncetd(S)) • innermost(S) = repeat(oncebu(innermost(S))) • outermost(S) = repeat(oncetd(outermost(S)))
Constructeurs élémentaires • Identity • Fail • Sequence • Choice • All • One • mu
Utilisation • Une stratégie est de type VisitableVisitor • VisitableVisitor s = `Identity(); • Un terme est de type Visitable • Visitable t = `a(); • Une stratégie peut s’appliquer sur un terme • Visitable result = s.visit(t); • Une stratégie préserve le type • Term t = `a(); • Term result = (Term) s.visit(t);
Définition de stratégies VisitableVisitor Try(VisitableVisitor S) { return `Choice(S,Identity()); } VisitableVisitor Repeat(VisitableVisitor S) { return `mu(MuVar("x"),Choice(Sequence(S,MuVar("x")),Identity())); } VisitableVisitor OnceBottomUp(VisitableVisitor S) { return `mu(MuVar("x"),Choice(One(MuVar("x")),S)) } } • Exercice implanter innermost(a b)
Stratégie élémentaire en Tom %strategy RewriteSystem extends `Fails() { visit Term { a() -> { return `b(); } } } VisitableVisitor S = `Repeat(OnceBottomUp(RewriteSystem())) Term result = S.visit(`f(a(),g(b(),a())));
Utilisations VisitableVisitor rule = new RewriteSystem(); Term subject = `f(g(g(a,b),g(a,a))); `OnceBottomUp(rule).visit(subject); `Innermost(rule).visit(subject); `Repeat(OnceBottomUp(rule)).visit(subject);
(mode paranoïaque) VisitableVisitor rule = new RewriteSystem(); Term subject = `f(g(g(a,b),g(a,a))); VisitableVisitor onceBottomUp = `mu(MuVar("x"),Choice(One(MuVar("x")),rule)); onceBottomUp.visit(subject)); VisitableVisitor innermostSlow = `mu(MuVar("y"),Choice(Sequence(onceBottomUp,MuVar("y")),Identity())); innermostSlow.visit(subject)); VisitableVisitor innermost = `mu(MuVar("x"),Sequence(All(MuVar("x")),Choice(Sequence(rule,MuVar("x")),Identity))); innermost.visit(subject));
Questions • Comment calculer des ensembles de résultats • Exemples • f(g(g(a,b),g(a,b))) • trouver les x tels que g(x,b) filtre un sous terme
Solution • considerer • s(col) : g(x,b) col.add(x) • appliquer • Try(BottomUp(s(col))) • énumérer col
Codage %strategy RewriteSystem(c:Collection) extends Identity() { visit Term { g(x,b()) -> { collection.add(`x); } } } Collection collection = new HashSet(); VisitableVisitor rule = `RewriteSystem(collection); Term subject = `f(g(g(a,b),g(c,b))); `Try(BottomUp(rule)).visit(subject); System.out.println("collect : " + collection);