Cours num´ero 2: environnements – fonctions

publicité
Les fonctions en OC AML
Qu’est-ce qu’une fonction en OC AML ?
Cours numéro 2: environnements – fonctions –
fonctions récursives
C’est une valeur comme une autre (au même titre qu’un int, un
float ou un char).
LI213 – Types et Structures de données
Conséquences :
une fonction a un type
Christophe Gonzales – Pierre-Henri Wuillemin
on peut créer des liaisons dont la valeur est une fonction
(≈ affecter une fonction à un identifiant)
Licence d’Informatique – Université Paris 6
on peut créer des fonctions visibles uniquement dans un
environnement local
etc
Christophe Gonzales – Pierre-Henri Wuillemin
Types des fonctions
Cours numéro 2: environnements – fonctions – fonctions récursives
Application de fonction
Notations des types des fonctions
Comment appliquer une fonction ?
Vus dans le manuel de référence (core library, module
Pervasives) :
Écrire le nom de la fonction suivi de son (ou ses) argument(s),
le tout séparé par des espaces (comme en Scheme)
int of float : float -> int
int of float prend en argument un float et renvoie un
int
Exemple :
mod float de type : float -> float -> float
# mod float 3.4 2.;;
mod float : float -> float -> float
mod float prend deux arguments (des float) et renvoie
le float égal au reste de la division du premier argument
par le deuxième.
- : float = 1.4
Règle : le type d’une fonction est obtenu en écrivant le type de
ses arguments suivi du type de retour de la fonction, le tout
séparé par des ->
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
ne pas mettre les arguments entre parenthèses séparés
par des «,» (voir le cours sur les n-uplets)
# mod float (3.4,2.);;
This expression has type float * float
but is here used with type float
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Déclaration d’une fonction (1/3)
Déclaration d’une fonction (2/3)
let f x = x + 1 ;;
Comment créer une fonction
Trois manières différentes :
1
let f x = x + 1 ;; (méthode préférée)
noms des paramètres : placés entre le nom de la fonction
et le signe =
2
let f = function x -> x + 1 ;;
chaque paramètre est placé entre un mot-clé function et
une -> (moins, supérieur)
Type de la fonction
f : int -> int
le type du premier argument, suivi d’une flèche suivie du type
du deuxième argument, suivi d’une flèche, ..., suivi d’une flèche
suivie du type de valeur retournée par la fonction
=⇒ impossible de déclarer :
# let f x = if x < 4 then 3.5 else 6;;
let f = fun x -> x + 1 ;;
3
car la valeur retournée n’aurait pas un type bien défini (float si
x < 4 ou int si x ≥ 4)
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Déclaration d’une fonction (3/3)
Soit l’environnement E = b(x,7.6), (y,-7.8), ...c
let f x y = x + y + 1 ;;
# let x au plus pres = int of float (x +. 0.5)
and y au plus pres = int of float (y -. 0.5);;
Valeur de la fonction
La valeur d’une fonction est sa fermeture notée :
y
Cours numéro 2: environnements – fonctions – fonctions récursives
Exemple d’application de fonction
Soit l’environnement E
x
Christophe Gonzales – Pierre-Henri Wuillemin
val x au plus pres : int = 8
val y au plus pres : int = -8
x + y + 1, E
Elle est caractérisée par :
les noms des paramètres formels (x,y)
le corps de la fonction (x + y + 1)
l’environnement E dans lequel la fonction a été définie
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Évaluation : x +. 0.5 est évalué dans l’environnement E =⇒ 8.1
puis int of float est appliqué à 8.1 =⇒ l’entier 8
Pourquoi faut-il des parenthèses ?
Sinon OC AML parenthèse de la manière suivante :
let x au plus pres = (int of float x) +. 0.5
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Évaluation d’une application de fonction (1/4)
Évaluation d’une application de fonction (2/4)
# let y = 3 ;;
let f x = if y = 2 then x else x - 2 ;;
let y = 2 ;;
f 3;;
Mécanisme d’évaluation de f x
y+1, Env f) C Env fc
Soit E = b(x,3),...,(f,y
l’environnement dans lequel on applique f x ;;
1
x est évalué dans l’environnement courant E =⇒ 3
2
f est évaluée dans E =⇒ fermeture :
y
y+1, Env f
3
on crée un env local E loc = b(y,3) C Env fc :
on rajoute donc à Env f une liaison entre y, le paramètre
formel de f, et sa valeur (3)
puis E1 = b(y,3) C E0 c
4
On évalue le corps de f (ici y + 1) dans E loc =⇒ 4
puis E2 = b(f,x
5
On retourne la valeur 4 et on détruit E loc
puis E3 = b(y,2),(f,x
Que vaut f 3 ? 3 ou 1 ?
Indice : constituer l’environnement :
Au départ, environnement E0
..., E1 ),(y,3) C E0 c
..., E1 ),(y,3) C E0 c
f 3 est évaluée dans E3
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Évaluation d’une application de fonction (3/4)
..., E1 ),(y,3) C E0 c
1
3 est évalué dans E3 =⇒ 3
2
f est évalué dans E3 =⇒ fermeture :
x
if y = 2 then x else x - 2, E1 3
on crée un environnement local E loc = b(x,3) C E1 c
4
on évalue if y = 2 then x else x - 2 dans E loc ⇒ 1
5
on retourne 1 et on détruit E loc
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Évaluation d’une application de fonction (4/4)
# let y = 3 ;;
let f x = if y = 2 then x else x - 2 ;;
let y = 2 ;;
f 3;;
E1 = b(y,3) C E0 c
E3 = b(y,2),(f,x
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Règle : Les valeurs des «identifiants» utilisées dans le corps
d’une fonction (exceptés celles des paramètres formels) sont
celles que ces identifiants avaient lors de la déclaration de la
fonction
=⇒ vous pouvez définir de nouvelles liaisons avec des
identifiants utilisés dans une fonction, cela n’a aucun impact sur
la fonction.
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Les fonctions à plusieurs paramètres
Application partielle (1/2)
# let f x y = x + y
and g = function x -> function y -> x + y
and h = function x -> (function y -> x + y);;
Application partielle : appliquer une fonction en lui passant ses
premiers mais pas l’ensemble de ses arguments
val f : int -> int -> int = <fun>
val g : int -> int -> int = <fun>
val h : int -> int -> int = <fun>
# let f x y = x + y ;;
let g = f 3 ;;
g 2;;
Fonctions à plusieurs paramètres
function x -> function y -> x + y
⇔ function x -> (function y -> x + y)
val f : int -> int -> int = <fun>
val g : int -> int = <fun>
- : int = 5
=⇒ une fonction à n paramètres est une fonction à un seul paramètre renvoyant une fonction à n − 1 paramètres
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Application partielle (2/2)
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Les fonctions récursives
# let f x y = x + y ;;
let g = f 3 ;;
g 2;;
# let fact x =
if x = 0 then 1
else x * (fact (x-1));;
E1 = b(f,x
Unbound value fact
1
2
3
4
5
6
7
8
y
x+y, E0 ),...c
on évalue 3 dans E1 =⇒ 3
on évalue f dans E1 =⇒ x
y
x+y, E0 on crée E2 = b(x,3) C E0 c
on évalue le corps de la fonction dans E2 =⇒ fonction
y
x+y dans l’environnement E2 = y
x+y, E2 x+y, E2 ) C E1 c
on modifie l’env : E3 = b(g,y
on récupère valeur de 2 et la fermeture de g dans E3
on crée E4 = b(y,2) C E2 c
on évalue x + y dans E4 =⇒ 5
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
problème : si on veut évaluer f 3, on fait appel à f 2.
Or f n’appartient pas à l’environnement de la fermeture de f !
Règle : pour déclarer une fonction récursive, utiliser let rec
=⇒ rajoute une liaison entre f et sa fermeture dans
l’environnement de la fermeture de f
# let rec f x =
if x = 0 then 1
else x * (f (x-1));;
val f : int -> int = <fun>
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Les fonctions récursives imbriquées
La pile d’exécution (1/2)
on veut déclarer deux fonctions f et g telles que f appelle g et g
appelle f =⇒ f doit appartenir à la fermeture de g et g doit
appartenir à la fermeture de f
Exécution d’une fonction :
# let f x = x + 1;;
Règle : pour déclarer des fonctions récursives imbriquées,
utiliser let rec ... and ...
let y = f 3 in
y + 2;;
# let rec pair x =
if x = 0 then true else impair (x-1)
and impair x =
if x = 0 then false else pair (x-1) ;;
pair 3;;
2 problèmes :
val pair : int -> bool = <fun>
val impair : int -> bool = <fun>
- : bool = false
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
La pile d’exécution (2/2)
3
1
comment retourner la valeur de f 3 à y ?
2
comment savoir quelle est la prochaine instruction à
exécuter après la fin de la fonction ?
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Limite de la pile d’exécution
# let f x = x + 1;;
let y = f 3 in
y + 2;;
Problème : la pile d’exécution n’a pas une taille infinie
=⇒ nombre limité d’appels de fonctions
Exemple
# let rec f x = x + f x;;
Pile d’exécution
val f : int -> int = <fun>
1
copier sur la pile d’exécution les paramètres, l’adresse de
la prochaine instruction à exécuter après f 3, etc
2
f utilise la pile pour la valeur des paramètres
3
f stocke la valeur à retourner dans la pile
4
la pile indique quelle liaison effectuer pour y et quelle est
la prochaine instruction à exécuter
5
# f 3;;
Stack overflow during evaluation
(looping recursion ?).
Est-ce une fatalité ?
Pas en OC AML ! !
on dépile l’appel à la fonction f
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Les fonctions récursives non terminales
Les fonctions récursives terminales (1/4)
# let f x =
let rec g somme x = g (somme + x) (x+1) in
g 0 x;;
Récursivité non terminale
# let rec f x = x + f (x + 1);;
Cette fonction calcule la même somme que celle du transparent
précédent mais elle s’exécute indéfiniment. Pourquoi ?
f 3 =⇒ calculer 3 + f 4
=⇒ on ne peut calculer la somme avant de connaı̂tre la
valeur de f 4
=⇒ lorsque l’on exécute f 4, il reste des calculs en
suspens (la somme)
=⇒ on est obligé d’empiler le nouvel appel à f 4
=⇒ la pile grossit et elle explose
Christophe Gonzales – Pierre-Henri Wuillemin
f 3 =⇒ renvoyer g 0 3
=⇒ renvoyer g 3 4
=⇒ renvoyer g 7 5
=⇒ renvoyer g 12 6, etc
Imaginons que la valeur retournée par g 12 6 soit 30
Alors val retournée par g 7 5 = val retournée par g 3 4 = 30
=⇒ inutile de stocker plusieurs fois cette valeur dans la
pile d’exécution.
Cours numéro 2: environnements – fonctions – fonctions récursives
Les fonctions récursives terminales (2/4)
Cours numéro 2: environnements – fonctions – fonctions récursives
Les fonctions récursives terminales (3/4)
# let f x =
let rec g somme x = g (somme + x) (x+1) in
g 0 x;;
Lorsque g 12 6 se termine,
on revient à g 7 5 qui se termine,
qui revient à g 3 4 qui se termine, etc
=⇒ Lorsqu’un appel à une fonction g se termine, tous les appels
précédents se terminent aussi
=⇒ inutile de stocker toutes les adresses de retour dans la pile
d’exécution, seule celle de g 3 4 suffit
Christophe Gonzales – Pierre-Henri Wuillemin
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
# let f x =
let rec g somme x = g (somme + x) (x+1) in
g 0 x;;
Conclusion :
on n’a pas besoin de conserver plusieurs
valeurs de retour dans la pile
on n’a pas besoin de conserver plusieurs
adresses de retour
4
3
=⇒ plutôt que d’empiler les nouveaux appels à g,
substituer dans la pile les informations relatives aux
anciens appels de g par celles des nouveaux appels
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Les fonctions récursives terminales (4/4)
Récursivité terminale : définition
Une fonction récursive f dans laquelle lorsqu’un appel à f est
réalisé, aucun calcul n’est en suspens.
Ces appels n’occasionnent pas d’accroissement de la taille de
la pile d’exécution.
Christophe Gonzales – Pierre-Henri Wuillemin
Cours numéro 2: environnements – fonctions – fonctions récursives
Téléchargement