Evaluation d'une expression Sans variable libre Vu dans le châpitre 2 Avec variables libres #pi *. r *. r ;; #let f = fun x -> if v > 3*2 then x+3 else x*x*3 + v;; Les variables qui apparaissent libres dans l'expression (pi et r dans la première et v dans la seconde) doivent avoir été définies au préalable. L'interpréteur doit trouver dans l'environnement les valeurs auxquelles elles sont liées.
Les notions de base Liaison C'est un couple (i, v) ou i est un identificateur et v une valeur. On dit que i est liee a v. Environnement C'est une liste de liaisons Environnement initial: E 0 C'est l'environnement chargé quand on lance Ocaml. Définition globale Rajoute une liaison à l'environnement courant
Exemple Environnement: E 0 #let pi = 3.14 ;; (pi, 3.14) :: E 0 # let r = 2.1 ;; (r, 2.1) :: (pi, 3.14) :: E 0 #let s = pi*.r*.r ;; (s, 13.8474) :: (r, 2.1) :: (pi, 3.14) :: E 0 #let pi = 3.1416 ;; (pi, 3.1416) :: (s, 13.8474) :: (r, 2.1) :: (pi, 3.14) :: E 0 L'ancienne valeur de pi n'est plus accessible # pi;; - : float = 3.1416
Définitions en parallèle Toutes leurs évaluations se font dans l'environnement courant Celui-ci est ensuite modifié # let x = 0;; #let x = 3 and y= x+1;; x : int = 3 y : int = 1 Environnement courant E (x, 0) :: E (x,3) :: (y,1) :: (x, 0) :: E
Définitions locales Modifient momentanément l'environnement C'est dans cet environnement modifié que se fait l'évaluation de l'expression sur laquelle elles portent In fine, l'environnement est inchangé
Environnement courant: #let x = 10 in x+1;; Définitions locales: exemples (x,3) :: (y,1) :: (x, 0) :: E x+1 évaluée dans (x, 10) :: (x,3) :: (y,1) :: (x, 0) :: E - : int = 11 Environnement courant: (x,3) :: (y,1) :: (x, 0) :: E #let x=x+1 and y=x+2 in x+y;; x+1 et y évalués dans l'environnement courant x+y évalué dans (x,4) ::(y,5):: (x,3) :: (y,1) :: (x, 0) :: E - : int = 9 Environnement courant: (x,3) :: (y,1) :: (x, 0) :: E
Définitions locales: exemples Environnement courant: (x,3) :: (y,1) :: (x, 0) :: E #let x = x+1 in let y = x+2 in x+y;; x+1 évaluée dans l'environnement courant y est évalué dans (x, 4) :: (x,3) :: (y,1) :: (x, 0) :: E x+y évaluée dans (y,6) :: (x, 4) :: (x,3) :: (y,1) :: (x, 0) :: E - : int = 10 Environnement courant: (x,3) :: (y,1) :: (x, 0) :: E
Evaluation des fonctions Fermetures Soit une fonction non récursive définie par: let f = fun x -> corps Châpitre 2 : fun x -> corps est sous forme réduite et peut donc être considéré comme la valeur de f. Ceci est (presque) vrai en l'absence de VL (variables libres) (dans les implantations corps est simpifié) Cette définition pourrait ainsi rajouter à l'environnement courant la liaison : (f, fun x -> corps) Quid des définitions de fonctions avec variables libres? Quid des définitions récursives?
Evaluation des fonctions Fermetures Exemple #let v = 2;; #let f = fun x -> if v > 3*2 then x+3 else x*x*3 + v;; VL(corps) : v, valeur à chercher dans l'environnement E La valeur de f est un couple Let f = fun x -> corps < fun x -> simpl(corps), E > simpl(corps): simplification de corps E: environnement au moment de la définition de f
Evaluation des fonctions Nouvel environnement: Fermetures let f = fun x -> corps (f, <fun x -> simpl(corps), E> ) :: E Fermeture Car toute VL de simpl(corps) autre que x est liée dans E. Ce couple ne contient aucune VL dont la valeur n'est pas définie. En ce sens, il est fermé. On n'évalue pas mais on enregistre dans la fermeture tous les renseignements pour évaluer ultérieurement, au moment de l'application à un argument.
Evaluation des fonctions Liaisons statiques (ou lexicales) des VL Environnement courant : E 0 #let v = 2;; (v,2) :: E 0 #let f x = if v > 3*2 then x+3 else x*x*3 + v;; (f, < fun x -> x*x*3+v, (v,2)::e 0 >) :: (v,2)::e 0 #let v = 100;; (v,100) :: (f, < fun x -> x*x*3+v, (v,2)::e 0 >) :: (v,2)::e 0 Le v de corps f sera toujours évalué dans l'env. tel qu'il était au moment de la définition de f (enregistré dans la fermeture). La rédéfiniton ultérieure de v n'affecte en rien la valeur de f : liaison statique
Evaluation des applications Evaluation par valeur Evaluation de (e 1 e 2 ) dans l'environnement E Evaluation de e 1 dans E : v 1 = < fun x ->corps, E' > Evaluation de e 2 dans E : v 2 Evaluation de corps dans (x, v 2 ) :: E' Dans corps, x est remplacé par v 2 et les autres variables par leur valeur dans E' E est inchangé
Evaluation des applications Evaluation par valeur E = (v,100) :: (f, < fun x -> x*x*3+v, (v,2)::e 0 >) :: (v,2):: E 0 #f (2*v);; - : int = 120002 2*v évalué dans E : 200 f évaluée dans E : < fun x -> x*x*3+v, (v,2)::e 0 > x*x*3+v dans (x,200) :: (v,2)::e 0 : 200*200*3+2 = 12002
Evaluation des applications Evaluation par valeur E = (v,100) :: (f, < fun x -> x*x*3+v, (v,2)::e 0 >) :: (v,2):: E 0 #f (2*v);; - : int = 120002 2*v évalué dans E : 200 f évaluée dans E : < fun x -> x*x*3+v, (v,2)::e 0 > x*x*3+v dans (x,200) :: (v,2)::e 0 : 200*200*3+2 = 12002
Evaluation des applications Evaluation par nom de (e 1 e 2 ) dans l'environnement E Evaluation de e1 dans E : v 1 = < fun x ->corps, E'> Evaluation de corps dans (x, <e2, E>) :: E' Ce qui ne change pas: Les VL de corps autres que x sont évaluées dans E' Ce qui change: Les valeurs des variables sont des fermetures car elles ne sont pas évaluées immédiatement. On évalue corps avant e2 la valeur de e 2 dans l'environnement courant est calculée à chaque occurrence de x dans corps
Evaluation des fonctions récursives Etude d'un exemple Dans l'environnement E' on définit: #let rec fact = fun n -> if n = 0 then 1 else n * fact(n-1);; Par analogie avec les fonctions non récursives, la valeur de fact serait la fermeture définie par: @_fact = < fun n -> if n=0 then 1 else n * fact(n-1), E' > Mais le corps contient une variable libre: fact, qui n'est pas dans E'. Le couple n'est pas fermé et on ne saura où trouver la valeur de fact quand on évaluera le corps lors d'une application.
Evaluation des fonctions récursives Etude d'un exemple Dans l'environnement E' on définit: #let rec fact = fun n -> if n = 0 then 1 else n * fact(n-1);; @_fact = < fun n -> if n=0 then 1 else n * fact(n-1), E' > Exemple (fun n -> if n=0 then 1 else n * fact(n-1)) 2 Dans le corps, n est remplacé par 2. Mais par quoi est remplacé fact? E' ne rien là-dessus!
Evaluation des fonctions récursives Etude d'un exemple Dans l'environnement E' on définit: #let rec fact = fun n -> if n = 0 then 1 else n * fact(n-1);; @_fact = < fun n -> if n=0 then 1 else n * fact(n-1), E' > Il est nécessaire de rajouter dans l'environnement de la fermeture... la liaison de la variable fact qui est : (fact,?)
Evaluation des fonctions récursives Etude d'un exemple Dans l'environnement E' on définit: #let rec fact = fun n -> if n = 0 then 1 else n * fact(n-1);; @_fact = < fun n -> if n=0 then 1 else n * fact(n-1), E' > Il est nécessaire de rajouter dans l'environnement de la fermeture... la liaison de la variable fact qui est : (fact, @_fact)
Evaluation des fonctions récursives Etude d'un exemple Dans l'environnement E' on définit: #let rec fact = fun n -> if n = 0 then 1 else n * fact(n-1);; @_fact = < fun n -> if n=0 then 1 else n * fact(n-1), E' > Il est nécessaire de rajouter dans l'environnement de la fermeture... la liaison de la variable fact qui est : (fact, @_fact) On obtient: @_fact = < fun n -> if n=0 then 1 else n * fact(n-1), (fact, @_fact)::e' >
Evaluation des fonctions récursives Etude d'un exemple Dans l'environnement E' on définit: #let rec fact = fun n -> if n = 0 then 1 else n * fact(n-1);; @_fact = < fun n -> if n=0 then 1 else n * fact(n-1), E' > Il est nécessaire de rajouter dans l'environnement de la fermeture... la liaison de la variable fact qui est : (fact, @_fact) On obtient: @_fact = < fun n -> if n=0 then 1 else n * fact(n-1), (fact, @_fact)::e' > Définition circulaire!
Evaluation des fonctions récursives Etude d'un exemple Dans l'environnement E' on définit: #let rec fact = fun n -> if n = 0 then 1 else n * fact(n-1);; On obtient donc un nouvel environnement Avec E = (fact, @_fact) :: E' @_fact = < fun n -> corps, (fact, @_fact) :: E' > I.E. @_fact = < fun n -> corps, E > en posant corps = if n = 0 then 1 else n * fact(n-1)
Evaluation des fonctions récursives Etude d'un exemple @_fact = < fun n -> corps, (fact, @_fact):: E' > Il s'agit d'un terme infini: On peut remplacer @_fact dans la fermeture par sa valeur (on déplie) et on obtient: @_fact = < fun n -> corps, (fact, < fun n -> corps, (fact, @_fact):: E' >):: E' >
Evaluation des fonctions récursives Etude d'un exemple @_fact = < fun n -> corps, (fact, @_fact):: E' > @_fact = < fun n -> corps, (fact, < fun n -> corps, (fact, @_fact):: E' >):: E' > En redépliant, on obtient:
Evaluation des fonctions récursives Etude d'un exemple @_fact = < fun n -> corps, (fact, @_fact):: E' > @_fact = < fun n -> corps, (fact, < fun n -> corps, (fact, @_fact):: E' >):: E' > En redépliant, on obtient: @_fact = < fun n -> corps, (fact, < fun n -> corps, (fact, < fun n -> corps, (fact, @_fact):: E' >) :: E' >) :: E' >
Evaluation des fonctions récursives Etude d'un exemple L'idée est que ces termes circulaires sont dépliés autant de fois que nécessaire à l'évaluation d'un application, pas plus, pas moins.
Evaluation des fonctions récursives Evaluation de (fact 2) dans E. -> Evaluation de fact dans E: -> @_fact = <fun n-> if n=0 then 1 else n*fact(n-1), E> -> Evaluation de n*fact(n-1) dans E2 = (n,2)::e -> Evaluation de fact (n-1) dans E2 -> Evaluation de n-1 dans E2 -> 1 -> Evaluation de fact dans E2 - > @_fact -> Evaluation de n*fact(n-1) dans E1 = (n,1)::e E1 est empile sur E2
Evaluation des fonctions récursives -> Evaluation de fact (n-1) dans E1 = (n,1)::e -> Evaluation de (n-1) dans E1 -> 0 -> Evaluation de fact dans E1 -> @_fact -> Evaluation de if n=0 then 1 else n*fact(n-1) dans E0 = (n,0)::e E0 est empile sur E1 -> 1 E0 est dépilé. On se retrouve dans E1 -> Evaluation de n -> 1 -> Evaluation de 1*1 ->1 E1 est depilé. On se retrouve dans E2 -> Evaluation de n ->2 -> Evaluation de 2*1 = 2