Visiteur Vs Case Of

Version case of (avec elm)
L évaluation d une expression arithmetique est recursive, Plus Moins et Fois operent sur des Expressions.
Par exemple “2 + (3*4)” est une expression composée elle même de deux expressions:
- 2
- 3*4
Définition d’une expression
type Expr = Plus Expr Expr
| Moins Expr Expr
| Fois Expr Expr
| Const Float
L’exemple précédent s’écrit : Plus( (Const 2) , Fois ( Const(3) , Const (4)))
Fonction d’évaluation
eval : Expr -> Float
eval o =
case o of
Plus x y -> (eval x ) + (eval y)
Moins x y -> (eval x ) - (eval y)
Fois x y -> (eval x ) * (eval y)
Const x -> x
Déroulement de l’évaluation :
- eval ( Plus (Const 2) (Fois (Const 3)(Const 4)))
- Ici X = Const 2, et Y = Fois (Const 3)(Const 4)), Donc :
- eval ( Plus (Const 2) (Fois (Const 3)(Const 4))) -> (eval (Const 2)) + (eval(Fois (Const 3)(Const 4)))
- On peut remplacer eval(Const 2) par 2, on obtient :
- 2 + (eval(Fois (Const 3)(Const 4))) Ici X = (Const 3) et Y = (Const 4) Donc :
- 2 + (eval (Const 3)) * (eval(Const 4))
- On peut remplacer eval(Const 3) par 3 et eval(Const 4) par 4 on obtient : 2 + (3*4) = 2 + 12 = 14
Version visitor (avec Java)
Interface Visiteur
public interface Visiteur<R>{
public R visitConstante(Constante constante);
public R visitProd(Prod prod);
public R visitMoins(Moins moins);
public R visitPlus(Plus plus);
public R visitPuissance(Puissance puissance);
}
Interface ExpressionAVisiter
Elle a une seule méthode : accept . Laquelle prend en entrée un visiteur de type R et retourne une valeur de type R.
public interface ExpressionAVisiterr {
public <R> R accept(Visiteur<R> e1);
}
Définition des opérateurs
Plus
public class Plus implements Expr{
private Expr expr1;
private Expr expr2;
public Plus(Expr expr1 , Expr expr2){
this.expr1 = expr1;
this.expr2 = expr2;
}
public <R> R accept (Visiteur<R> visiteur ){
return visiteur.visitPlus(this);
}
//à définir : getExpr1();getExpr2()
}
Les opérateurs Prod et Moins sont construits de la même manière, c’est la méthode accept qui change.
Moins
public <R> R accept (Visiteur<R> visiteur ){
return visiteur.visitMoins(this);
}
Prod
public <R> R accept (Visiteur<R> visiteur ){
return visiteur.visitProd(this);
}
Le cas de Constante est un peu différent puisqu’il son opérande n’est pas une expression mais une valeur numérique
Constante
public class Constante implements Expr{
private double valeur;
public Constante (double valeur){
this.valeur = valeur;
}
public <R> R accept (Visiteur<R> visiteur ){
return visiteur.visitConstante(this);
}
//à définir : getValeur();
}
Classe VisiteurCalculReel
public class VisiteurCalculReel implements Visiteur<Double> {
public Double visitConstante(Constante constante){
return constante.getValeur();
}
public Double visitProd(Prod prod){
Double evalExpr1 = prod.getExpr1().accept(this);
Double evalExpr2 = prod.getExpr2().accept(this);
return evalExpr1 * evalExpr2;
}
public Double visitMoins(Moins moins){
Double evalExpr1 = moins.getExpr1().accept(this);
Double evalExpr2 = moins.getExpr2().accept(this);
return evalExpr1 - evalExpr2;
}
public Double visitPlus(Plus plus){
Double evalExpr1 = plus.getExpr1().accept(this);
Double evalExpr2 = plus.getExpr2().accept(this);
return evalExpr1 + evalExpr2;
}
public Double visitPuissance(Puissance puissance){
Double evalExpr1 = puissance.getExpr1().accept(this);
double n = puissance.getN();
return Math.pow(evalExpr1 , n);
}
}
On viste l’expression : new Plus (new Constante(2) , new Produit(new Constante(3) , new Constante(4)))
On obtient successivement :
- (new Constante(2)) + (new Produit(new Constante(3) , new Constante(4)))
- 2 + ((new Constante(3) * new Constante(4)))
- 2 + ( 3 * 4)
- 14
Et si ?
Et si on voulait ajouter un opérateur?

Par exemple comment ajouter les opérateurs cosinus, sinus et tangeante?
Dans les deux cas il faut :
- les ajouter au type expression
- définir leur calcul
Donc en elm :
type Expr = Plus Expr Expr
| Moins Expr Expr
| Fois Expr Expr
| Const Float
devient
type Expr = Plus Expr Expr
| Moins Expr Expr
| Fois Expr Expr
| Const Expr
| Cos Expr
| Sin Expr
| Tan Expr
et trois cas doivent être ajoutés à éval
- Cos x -> cos(eval x )
- Sin x -> sin(eval x )
- Tan x -> tan(eval x )
En java c’est exactement le même principe.
On ajoute trois nouvelles méthodes à l’interface Visiteur
public interface Visiteur<R>{
//.....
public R visitCos(Cosinus cosinus);
public R visitSin(Sinus sinus);
public R visitTan(Tan tan);
}
Avec les trois classes correspondantes
public class Cosinus implements Expr{
private Expr expr1;
public Cosinus(Expr expr1){
this.expr1 = expr1;
}
public <R> R accept (Visiteur<R> visiteur ){
return visiteur.visitCos(this);
}
//à définir : getExpr1();
}
Sinus et Tan sont similaires, seule la fonction accept est modifiée :
public <R> R accept (Visiteur<R> visiteur ){
return visiteur.visitSin(this);
}
public <R> R accept (Visiteur<R> visiteur ){
return visiteur.visitTan(this);
}
Il faut maintenant indiquer comment ces expressions sont évaluées
Dans calcul :
public Double visitCos(Cosinus cosinus){
Double evalExpr1 = cosinus.getExpr1().accept(this);
return Math.cos(evalExpr1);
}
public Double visitSin(Sinus sinus){
Double evalExpr1 = sinus.getExpr1().accept(this);
return Math.sin(evalExpr1);
}
public Double visitTan(Tan tan){
Double evalExpr1 = tan.getExpr1().accept(this);
return Math.tan(evalExpr1);
}
Et si on voulait changer la méthode de calcul?

On pourrait vouloir visiter la même expression mais changer l’implémentation du visiteur. Par exemple
- Plus(d1,d2) = “(d1 + d2)”
- Moins(d1,d2) = “(d1 - d2)”
- Prod(d1,d2) = “(d1 * d2)”
Pour cela il faut ajouter une nouvelle classe : VisiteurOperationString, laquelle implémentera Visiteur.
Il faut uniquement définir les méthodes de l’interface Visiteur :
public class VisiteurCalculString implements Visiteur<String> {
public String visitConstante(Constante constante){
return String.valueOf(constante.getValeur());
}
public String visitProd(Prod prod){
String evalExpr1 = prod.getExpr1().accept(this);
String evalExpr2 = prod.getExpr2().accept(this);
return "(" + evalExpr1 + "*" + evalExpr2 +")";
}
public String visitMoins(Moins moins){
String evalExpr1 = moins.getExpr1().accept(this);
String evalExpr2 = moins.getExpr2().accept(this);
return "(" + evalExpr1 + "-" + evalExpr2 +")";
}
public String visitPlus(Plus plus){
String evalExpr1 = plus.getExpr1().accept(this);
String evalExpr2 = plus.getExpr2().accept(this);
return "(" + evalExpr1 + "+" + evalExpr2 +")";
}
public String visitPuissance(Puissance puissance){
String evalExpr1 = puissance.getExpr1().accept(this);
double n = puissance.getN();
return "(" + evalExpr1 + "^" + n +")";
}
}