Précédent Index Suivant

Sémantique de Scheme

 

 
Jusqu'à présent, nous avons vu les différentes constructions de Scheme en donnant une sémantique (qu'est-ce que fait l'évaluateur?) intuitive et en regardant (grâce au « pas à pas ») comment l'évaluateur tavaillait. Mais cette façon de faire a ses limites puisque nous ne pouvons pas utiliser le « pas à pas » de DrScheme pour n'importe quel programme (pas de let, pas de définition interne...). Aussi, dans cette section, nous voudrions donner une sémantique plus précise et plus générale.
 
Idée et problématique  
Commençons par une expression simple, lorsque l'on peut utiliser le « pas à pas »:  
;;; a-disque : Nombre -> Nombre 
;;; (a-disque r) rend la surface du disque de rayon «r» 
(define (a-disque r)
  (* 3.1416 r r))
 
;;; essai de a-disque (rend 1520.5344) : 
(a-disque (+ 20 2))
 

 
On peut visualiser le processus de calcul en utilisant DrScheme en mode pas à pas.
 
Comment çà marche? On veut calculer:
 
  (a-disque (+ 20 2))
 

 
Dans un premier temps, on doit calculer l'argument de la fonction:
 
  (a-disque (+ 20 2) )
 

 
les arguments de la fonction + sont des valeurs et, cette fonction étant une primitive, elle est calculée « d'un coup »:
 
--> (a-disque 22 )
 

 
et maintenant que fait-on?
 
La fonction a-disque n'est pas une primitive, elle a été définie par le programmeur: on prend sa définition, ou plutôt le corps de cette définition, dans laquelle on « remplace » la variable par la valeur de l'argument:
 

(a-disque 22)  
-->
 
(* 3.1416 22 22)
 
(define (a-disque r)
  (* 3.1416 r r))

 

 
encore une fois, pour cette application, la fonction est une primitive et les arguments sont des valeurs: le calcul s'effectue immédiatement:
 
(* 3.1416 22 22)  
-->
 
1520.5344
 

 
Terminologie: classiquement, en informatique, on ne dit pas qu'on « remplace » la variable par la valeur de l'argument mais l'on dit que l'on substitue, dans le corps de la fonction, la variable par l'argument. La sémantique de Scheme que nous vous présentons est appellée modèle par substitution.
 
Notion d'environnement  
Mais où trouve-t-on la définition de la fonction a-disque? Dans l'environnement dans lequel on évalue l'expression.
 
En informatique, cette notion d'environnement se décline à tous les niveaux:  
Une autre façon de voir les choses est de dire que l'environnement (quel que soit le niveau où l'on se place) est constitué de choses, de trucs, qui sont indispensables pour effectuer une tâche et que l'on n'a pas besoin de citer explicitement dans la description du traitement à effectuer: il faut d'autant plus avoir conscience de l'existence de cet environnement qu'il est absent du texte descriptif.
 
Modèle par substitution  
Ainsi, pour évaluer une expression, il faut aussi savoir dans quel environnement on se place.
 
Au départ -- on dit au top-level --, l'environnement est constitué par toutes les primitives (*, +... pair?, car...). On peut enrichir cet environnement en définissant des fonctions, le nouvel environnement comportant alors les primitives et les fonctions définies par le programmeur.
 
Ainsi, dans l'exemple précédent, lorsque l'on évalue l'expression (a-disque (+ 20 2)), l'environnement est constitué par les primitives et la définition de la fonction a-disque.
 
Premier exemple: on demande l'évaluation de:
 
;;; a-disque : Nombre -> Nombre 
;;; (a-disque r) rend la surface du disque de rayon «r» 
(define (a-disque r)
  (* 3.14 r r))
 
;;; v-cylindre : Nombre * Nombre -> Nombre 
;;; (v-cylindre r h) rend le volume du cylindre de rayon «r» 
;;; et de hauteur «h» 
(define (v-cylindre r h)
  (* (a-disque r) h))
 
;;; essai de v-cylindre (rend 4559.28) : 
(v-cylindre 22 3)
 

 
En indiquant dans la colonne de gauche l'environnement et dans celle de droite la liste des substitutions, on obtient:
 
Environnement Évaluation
 
(define (a-disque r)
 (* 3.14 r r))

 
(define (v-cylindre r h)
  (* (a-disque r) h))

 
 
(v-cylindre 22 3)  
-->
 
(* (a-disque 22) 3)  
-->
 
(* (* 3.14 22 22) 3)
 
-->
 
(* 1519.76 3)  
-->
 
4559.28
 

 
Second exemple: lorsque nous avons étudié la récursivité sur les listes, nous avons défini la fonction « concaténation droite » nommée conc-d:  
;;; conc-d : LISTE[alpha] * alpha -> LISTE[alpha] 
;;; (conc-d L x) rend la liste obtenue en ajoutant «x» à la fin de la liste «L» 
(define (conc-d L x)
  (if (pair? L)
      (cons (car L) (conc-d (cdr L) x))
      (list x)))
 
(conc-d '(a b) 'c)
 

 
Comment évalue-t-on l'expression (il s'agit d'une révision sur la récursivité)? L'environnement ne comporte que les primitives et la définition de la fonction conc-d. L'évaluation est alors:
 
(conc-d '(a b) 'c)
 
On substitue, dans la définition de conc-d, L par '(a b) et x par 'c:
 
-->
 
(if (pair? '(a b))
    (cons (car '(a b)) (conc-d (cdr '(a b)) 'c))
    (list 'c))  

 
L'expression est une alternative. On doit donc évaluer la condition, constituée par une application d'une primitive:
 
-->
 
(if #t
    (cons (car '(a b)) (conc-d (cdr '(a b)) 'c))
    (list 'c))  

 
La condition étant vraie, pour évaluer l'alternative, on doit évaluer sa conséquence:
 
-->
 
(cons (car '(a b)) (conc-d (cdr '(a b)) 'c))  

 
On évalue alors les deux sous-expressions:
 
--> -->
 
(cons 'a (conc-d '(b) 'c))  

-->  

 
Il faut alors évaluer (conc-d '(b) 'c). Pour ce faire, on substitue, dans la définition de conc-d, L par '(b) et x par 'c:
 
(cons 'a (if (pair? '(b))
             (cons (car '(b)) (conc-d (cdr '(b)) 'c))
             (list 'c)) )  

 
L'alternative est évaluée comme précédemment en évaluant la condition:  
-->
 
(cons 'a (if #t
             (cons (car '(b)) (conc-d (cdr '(b)) 'c))
             (list 'c)) )  

 
et comme cette dernière est vraie, on évalue la conséquence:  
-->
 
(cons 'a (cons (car '(b)) (conc-d (cdr '(b)) 'c)))  

 
On évalue les deux expressions (car '(b)) et (cdr '(b)):
 
--> -->
 
(cons 'a (cons 'b (conc-d '()'c) ))  

 
Il faut alors évaluer (conc-d '() 'c). Pour ce faire, comme d'habitude, on substitue, dans la définition de conc-d, L par '() et x par 'c:
 
-->  

 
(cons 'a
      (cons 'b
            (if (pair? '())
                (cons (car '()) (conc-d (cdr '()) 'c))
                (list 'c)) ))

 
et on évalue la condition:
 
-->
 
(cons 'a
      (cons 'b
            (if #f
                (cons (car '()) (conc-d (cdr '()) 'c))
                (list 'c)) ))

 
La condition étant fausse, on évalue l'alternant:  
-->
 
(cons 'a (cons 'b (list 'c) ))  

 
et, en deux pas (exécution de la primitive cons), on trouve:  
--> -->
 
(a b c)  

 

Pour s'auto-évaluer
  • Exercices d'assouplissement



  • Précédent Index Suivant