Types, Expressions, Fonctions et constructions du langages ocaml
Transcription
Types, Expressions, Fonctions et constructions du langages ocaml
Université Joseph Fourier UFR IMAG Département Licence Sciences et Technologie LICENCE SCIENCES & TECHNOLOGIES 1re année INF121 ALGORITHMIQUE ET PROGRAMMATION FONCTIONNELLE Introduction Vous connaisssez le langage C, pourquoi apprendre un nouveau langage ? langage Ce n'est pas le ocaml en lui-même qui est intéressant mais le modèle de programmation qui lui correspond : la programmation fonctionnelle. Ce modèle de programmation induit une nouvelle façon de décomposer et de résoudre un problème. Pour un informaticien il est important de connaître plusieurs modèles de programmation pour choisir celui qui est le plus adapté au problème qu'il doit résoudre, c'est-à-dire celui qui donnera le programme le plus simple, le plus élégant avec le moins d'eort et de risque d'erreur. Il n'y a pas de langage meilleur qu'un autre, ils sont tous aussi puissants : on sait que tout ce qu'on peut faire dans l'un peut être fait dans l'autre. Mais la solution s'exprime peut-être plus simplement dans l'un que dans l'autre. Par exemple, s'il s'agit de programmer une carte vidéo et de manipuler des tableaux ; C sera bien adapté. s'il s'agit de programmer des algorithmes qui ne travaillent pas sur des tableaux mais sur des structures récursives ; ce sera plus simple en . pour d'autes types de problèmes qui nécessitent de résoudre des contraintes ; le modèle de programmation logique par contrainte sera plus approprié. Ce ne sont que quelques exemples parmi la dizaine de modèles de programmation connus à ce jour. ocaml La programmation fonctionnelle en ocaml est-elle diérente de la programmation impérative en C ? Le langage C est un représentant parmi d'autres (Java,Pascal,...) des langages dits impératifs. Ils sont nommés ainsi pour indiquer que la programmation impérative consiste à donner des ordres à la machine, par exemple : x=3 : met la valeur 3 en mémoire dans la variable x ! for(i=0 ; i<5 ; i=i+1){...} : répète 5 fois . . . ! Le langage ocaml fait partie des langages dits foncionnels, nommés ainsi pour indiquer que la pro- grammation fonctionnel consiste à dénir des fonctions. Dans les langages fonctionnels, l'aectation et les itérations (for,while) n'existent pas. Les seuls points communs avec les langages impératifs sont le branchement conditionnel if...then...else... et la dénition de fonctions. Les langages fonctionnels sont issues de la collaboration entre mathématiciens et informaticiens : ils ont la rigueur des mathématiques ; ils reposent sur peu de concepts (type,fonction,récursivité) mais très puissants ; ils sont aussi expressifs que les autres langages ; ils insistent sur la dénition de types et la vérication de type permet d'éviter de très nombreuses erreurs de programmation ; ils apprennent à programmer en réechissant mathématiquement au problème. ils résolvent élégamment certains problèmes compliqués. Types, expressions, fonctions et constructions du langage ocaml 2 Table des matières 1 Les types de base 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 Les booléens . . . . . . . . . . . . . . . . . . . . . . Les nombres . . . . . . . . . . . . . . . . . . . . . . Les caractères . . . . . . . . . . . . . . . . . . . . . Les types séquences . . . . . . . . . . . . . . . . . . Le type Texte . . . . . . . . . . . . . . . . . . . . . 1.5.1 Opérations sur les données de type Texte . . 1.5.2 Généralisation des opérations sur les textes Le type Chaîne . . . . . . . . . . . . . . . . . . . . Opérations de conversion entre Texte et Chaîne . . Opérateurs de comparaison . . . . . . . . . . . . . 2 Dénition de types complexes 2.1 2.2 2.3 2.4 Dénir et nommer un type . . . . Dénir un type par énumération Construire un produit de types . Construire une somme de types . . . . . . . . . . . . . . . . . . . . . 3.1 3.2 3.3 3.4 3.5 4.1 4.2 4.3 4.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Expression conditionnelle . . . . . . . . . . . . . . . . . Nommage d'une expression . . . . . . . . . . . . . . . . Expression de ltrage . . . . . . . . . . . . . . . . . . . . Expression de ltrage avec condition . . . . . . . . . . . Filtrage avec condition versus conditionnelles imbriquées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Dénition de fonctions . . . . . . . . . . . . . . . . . . 3 Constructions du langage Ocaml . . . . . . . . . . . . . . La spécication : un contrat entre l'utilisateur et le programmeur Le programmeur est aussi l'utilisateur de ses propres fonctions . . Dénition de fonctions partielles = fonctions avec condition . . . Respectez la spécication laisse malgré tout de la liberté . . . . . 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 6 6 7 8 8 9 11 11 12 13 15 15 16 17 19 23 23 23 25 26 27 29 30 31 32 33 4 Chapitre 1 Les types de base définition (Type d'une expression) Les ordinateurs n'apprécient pas les ambiguités. Ils font la distinction entre l'entier naturel 1 et le réel 0.99999... . En mathématique les deux versions sont égales, tandis que pour un ordinateur, ces données sont de nature diérente1 , on dit qu'elles sont de type diérent. Notation Toutes les expressions manipulées en informatique sont typées et on utlise la notation e pour indiquer que l'expression e est de type T. : T Un type en informatique correspond à un ensemble de valeurs en mathématiques. Les mathématiciens et les informaticiens utilisent un vocabulaire et des notations diérentes mais équivalentes. On peut donc indiéremment parler de types ou d'ensembles. Remarque mathématique e∈T informatique se lit e : T se lit la valeur de e appartient à l'ensemble T la valeur de l'expression e est de type T Exemples Z 2×n∈Z 5 : int 5∈ 2 * n : int mathématique informatique Bool bool Z R int float Car Chaîne char string Les types de base sont limités mais il est possible de dénir de nouveaux types. On peut alors donner très précisement le type d'une fonction comme on le fait en mathématique. L'objectif de ce chapitre est de présenter les moyens de construire des types. 1 L'ordinateur n'utilise pas les mêmes quantités de mémoires pour stocker un entier ou un réel. 5 1.1 Les booléens Les booléens vrai et faux qui appartiennent à l'ensemble mathématique Bool sont notées true et false en et sont de type bool. ocaml Opérations Ocaml dénies sur les booléens français mathématique informatique type Ocaml des opérateurs a et b a∧b a && b bool → bool → bool a ou b a∨b a || b bool → bool → bool a ¬a not a bool → bool b1 = b2 (b1 = b2) bool → bool → bool b1 6= b2 (b1 <> b2) bool → bool → bool non égalité diérence Exercice 1.1 Construire les tables de vérités des opérateurs et , ou , non . Vériez vos tables de vérité en tp en tapant les expressions dans l'interpréteur Ocaml. 1.2 Les nombres Z Ocaml Z En , les entiers relatifs ( ) sont notés int. Contrairement à qui est inni, int est un ensemble ni : il contient uniquement les entiers représentables sur 32 ou 64 bits selon les processeurs. La taille des entiers int est donc limitée par les capacités du processeur. En , les réels ( ) sont notés float. Une donnée de type float a une taille et une précision limitée par la capacité du processeur. Pour raisonner nous utiliserons les ensembles mathématiques suivants : R Ocaml DÉFINITION MATHÉMATIQUE D'ENSEMBLES déf déf déf déf déf déf N = Z+ N∗ = N \ {0} Z∗ = Z \ {0} R∗ = R \ {0} R+ = {r | r ∈ R− = {r | ... ∧ r > 0} ........... et aussi déf déf N = {2k | 2N + 1 = { 2 .. ∈ ∧ N} ............ | .......... } les entiers naturels . . . . . . . . . . ........... les entiers naturels impairs } 6 Opérations Ocaml dénies sur les entiers et les réels mathématique informatique type Ocaml des opérateurs français addition a + b int → int → int a +. b float → float → float a - b int → int → int a -. b float → float → float a * b int → int → int a *. b float → float → float a b a /. b float → float → float a÷b a / b int → int → int a mod b a mod b int → int → int a+b soustraction a−b multiplication a×b division réelle division entière modulo 1.3 Les caractères L'ensemble des caractères est noté Car. Cet ensemble mathématique rassemble tous les caractères. Il correspond au type char en . En mathématique et en informatique les valeurs de type caractère sont notées entre guillemets simples (ex. 'c'). Pour faciliter le raisonnement on distingue plusieurs sous ensembles de caractères. Ocaml DÉFINITION MATHÉMATIQUE D'ENSEMBLES déf Minuscule = {'a', . . . , 'z'} déf Majuscule = {'A', . . . , 'Z'} déf Lettre = Minuscule ∪ Majuscule déf Chire = {'0', . . . , '9'} déf Espace = {' ', '\t'} déf Saut de ligne = {'\n'} déf Symbole = les autres caractères du clavier déf Car = Lettre ∪ Chire ∪ Espace ∪ Symbole ∪ Saut de ligne Opérations sur les données de type caractère Les seuls opérateurs binaires associés au type caractère sont les opérations de comparaison (<=,<,>,>=), le test d'égalité (=) et le test de diérence (<>) qui sont de type Car → Car → Bool. Nous utiliserons aussi les fonctions suivantes : SPÉCIFICATION MATHÉMATIQUE Code ascii d'un caractère Prol int-of-char : Car → N Sémantique : int-of-char (c) est le numéro du caractère c dans la table ascii 7 Exemples 1. int-of-char ('0') = 48 2. int-of-char ('a') = 97 SPÉCIFICATION MATHÉMATIQUE Caractère correspondant à un code ascii Prol char-of-int : N → Car Sémantique : char-of-int (n) est le neme caractère de la table ascii Exemples 1. char-of-int (49) = '1' 2. char-of-int (65) = 'A' 1.4 Les types séquences Les mathématiciens français et les informaticiens anglo-saxons utilisent un vocabulaire diérent pour parler des séquences : mathématique informatique séquence list séquence de caractères, en français character list, en anglais char list en Ocaml notée Séq (Car) en math exemple : [ 'o' ; 'c' ; 'a' ; 'm' ; 'l'] séquence d'entiers, en français notée Séq (Z) en math exemple : integer list, int list en anglais en Ocaml [ 1; 3; 5; 7; 9 ] La séquence vide est notée [ ] L'ensemble des séquences non vide d'éléments de type T est noté Séq (T )∗ . DÉFINITION MATHÉMATIQUE D'UN ENSEMBLE déf Séq (T )∗ = Séq (T ) \ { [ ] } 1.5 Le type Texte Texte désigne l'ensemble des séquences de caractéres (ex. ['o' ;'c' ;'a' ;'m' ;'l']). Le texte vide est noté [ ]. Texte∗ désigne l'ensemble des textes privé du texte vide. Plus précisement, on dénit l'ensemble Texte comme l'ensemble des séquences de caractères. 8 Texte DÉFINITION MATHÉMATIQUE DE L'ENSEMBLE déf Texte = Séq (Car) On traduit ensuite la dénition mathématique en un type informatique. DÉFINITION INFORMATIQUE DU TYPE texte type texte = char list ;; 1.5.1 Opérations sur les données de type Texte Le type Texte est muni des opérations dénies pour toute séquence (voir chapitre 2). - Concaténation L'opération de concaténation de deux séquences, noté @ permet de coller deux textes. L'opérateur ( @ ) a pour type .......... → .......... → Texte. Exemple ['o' ;'c'] @ ['a' ;'m' ;'l'] = ['o' ;'c' ;'a' ;'m' ;'l'] Question L'opération de concaténation peut-elle donner un texte vide ? - Ajout à gauche L'opérateur ( :: ) permet d'ajouter un caractère à gauche d'un texte, il a pour type → Texte → Exemple ....... .. .......... . 'o' :: ['c' ;'a' ;'m' ;'l'] = ['o' ;'c' ;'a' ;'m' ;'l'] Quels que soient c une valeur de type Car et t une valeur de type Texte, on a l'égalité c :: t = [c] @ t Propriété Autrement dit, ajouter un . . . . . . . . . . . . . . . à . . . . . . . . . . . d'un texte avec l'opérateur . . . . donne le même résultat que . . . . . . . . . . . . . . .er le texte . . . . fait d'un . . . . . . caractère et le . . . . . . . . t à l'aide de l'opérateur @ . - Tête La fonction hd est l'abbréviation du mot anglais head qui signie tête. SPÉCIFICATION MATHÉMATIQUE Premier caractère d'un texte Prol hd : Texte∗ → . . . . . . . Sémantique : hd (t) est le premier caractère du texte t Exemples 1. hd ['o'; 'c'; 'a'; 'm'; 'l'] = 'o' 2. hd [ ] provoque une erreur - Queue La fonction tl est l'abbréviation du mot anglais tail qui signie queue. SPÉCIFICATION MATHÉMATIQUE Texte sans son premier caractère Prol tl : Texte . . → . . . . . . . . . . Sémantique : tl (t) est le texte t privé de son premier caractère 9 Exemples 1. tl 2. tl ['o'; 'c'; 'a'; 'm'; 'l'] = ['c'; 'a'; 'm'; 'l'] [] provoque une erreur Complétez les pointillés avec les types des expressions. ∀t ∈ Texte, on a l'égalité t = hd (t) :: tl (t) Propriété | {z } ...... - Dernier |{z} ......... SPÉCIFICATION MATHÉMATIQUE Prol dernier : . . . . . . . . . . . . → Car Sémantique : dernier (t) est le dernier caractère du texte t Exemples 1. dernier ['o'; 'c'; 'a'; 'm'; 'l'] = 2. dernier [] - Début ...... ..................................... SPÉCIFICATION MATHÉMATIQUE Prol debut : . . . . . . . . . . . . → Texte Sémantique : debut (t) est le texte t privé de son dernier caractère Exemples 1. debut ['o'; 'c'; 'a'; 'm'; 'l'] = [ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ] 2. debut . . . provoque une erreur Complétez les pointillés avec les types des expressions pour trouver l'opérateur manquant. ...... z }| { ∗ ∀t ∈ Texte , on a l'égalité t = debut (t) . . . . [ dernier (t) ] Propriété | {z } ......... | {z ......... } Les fonctions hd, tl, dernier et début ne doivent pas être appliquées à un texte vide. Cela provoquerait une erreur d'exécution du programme signalée par Exception : message d'erreur . Remarque 10 Complétez les pointillés avec les types des expressions, trouvez les opérateurs manquants, en déduire la spécication de la fonction coeur et réaliser la fonction coeur à l'aide des fonctions précédentes sur les textes. Exercice ....... ∀t ∈ Texte, on a l'égalité t |{z} z }| { = hd (t) .... Prol coeur : . . . . . . dernier (t) . . z | .......... SPÉCIFICATION MATHÉMATIQUE .......... Texte z }| { coeur (t) }| {z { .......... } de la fonction coeur ............ → .......... Sémantique : coeur (t) retourne le texte t . . . . . . . . . de . . . . . . . . . . . . . . . . . . . . . . et de . . . . . . . . . . . . . . . . . . . ................ RÉALISATION INFORMATIQUE Algorithme : coeur (t) = . . . ( . . . . . . . . . . ( t )) 1.5.2 Généralisation des opérations sur les textes Les textes sont des séquences de caractères. Les opérations précédentes sur les textes peuvent s'appliquer à tout sorte de séquences. Par exemple, l'opération d'ajout à gauche peut s'appliquer à des séquences contenant des valeurs d'un type T quelconque. Exercice Prol ( :: ) : T → Séq (T ) → Séq (T ) En vous inspirant de cet exemple, complétez les prols génériques des opérateurs et des fonctions suivantes : . . . . . . . . . . . . . → . . . . . . . (T ) → Séq ( . . . ) Prol (@) : Prol hd : Séq (T )∗ → . . . Prol tl : . . . . . . . . . . . . . . . → Séq ( . . . ) Prol debut : . . . . . . . . . . . . . . . → Séq ( . . . ) Prol dernier : . . . . . . . . . . . . . ∗ → ... 1.6 Le type Chaîne Pour programmer on utilise souvent les chaînes de caractères qui ore une notation plus compacte que les séquence de caractères. Les chaînes de caractères sont notées entre des guillemets doubles ("). L'ensemble des chaînes de caractères est noté Chaîne. Le type correspondant à l'ensemble Chaîne est string. Ocaml 11 Opération de concaténation sur les données de type Chaîne SPÉCIFICATION MATHÉMATIQUE concaténation de chaînes de caractères ( ˆ ) : Chaîne → Chaîne → Chaîne Prol Exemples : 1. ("o" ˆ "caml") = ("oc" ˆ "aml") = . . . = ("oca" ˆ "ml") = ("ocam" ˆ "l") = "ocaml" 2. ("" ˆ "ocaml") = "ocaml" = ("ocaml" ˆ "") Propriété ∀ch ∈ Chaîne, on a l'égalité ("" ˆ ch) = ch = (ch ˆ "") 1.7 Opérations de conversion entre Texte et Chaîne Il ne faut pas confondre les chaînes de caractères de type Chaîne et les séquences de caractères de type Texte. Ce sont des données de nature diérente. Retenez que Chaîne 6= Texte. ; 'm'; 'l'] "ocaml" | {z } 6= |['o'; 'c'; 'a' {z } Chaîne Texte En revanche les fonctions ci-apprès permettent de passer des chaînes de caractères aux séquences de caractères et vice-versa. texte vers chaine tvc : Texte → Chaîne SPÉCIFICATION MATHÉMATIQUE Prol Exemples : 1. tvc ['o' ;'c' ;'a' ;'m' ;'l'] = "ocaml" 2. tvc [ ] = "" chaine vers texte cvt : Chaîne → Texte SPÉCIFICATION MATHÉMATIQUE Prol Exemples : 1. cvt "ocaml" = ['o' ;'c' ;'a' ;'m' ;'l'] 2. cvt "" = [ ] Propriété Complétez les pointillés avec le type des expressions. ............. 1. ∀t ∈ Texte, on a l'égalité z }| { cvt ( tvc (t) | {z .......... )= . } |{z} Texte Texte 2. ∀c ∈ ............. , on a l'égalité z }| { . . . . . . ( . . . . . . (c) ) = | {z Chaîne 12 } c |{z} ............. Remarque Prenez garde à ne pas confondre, le caractère 'a' Chaîne et ['a'] qui est de type Texte, c'est-à-dire Séq (Car). de type Car avec "a" qui est de type 1.8 Opérateurs de comparaison Les opérateurs de comparaison (<=,<,>,>=), le test d'égalité (=) et le test de non-égalité (6=) noté <> en sont dénis pour tous les types et sont automatiquement créés lorsqu'on dénit un nouveau type . Ils ont donc un prol générique : T → T → Bool. ocaml ocaml ocaml 13 14 Chapitre 2 Dénition de types complexes 2.1 Dénir et nommer un type Les dénition de types permettent de décrire des données très complexes manipulées par un programme et de leur donner des noms simples et intuitifs qui rendront les programmes plus compréhensibles. L'utilisation de noms bien choisis facilite la conception, la mise au point, la lecture, la maintenance et la réutilisation des programmes. DÉFINITION MATHÉMATIQUE D'UN ENSEMBLE déf Nom du type = ensemble mathématique DÉFINITION INFORMATIQUE D'UN TYPE type nom du type = | {z } une construction de type ocaml ;; en minuscule Le type Texte que nous avons déjà utilisé n'est pas un type prédéni du langage ocaml. On dénit l'ensemble des textes comme l'ensembles des séquences de caractères. Exemple DÉFINITION MATHÉMATIQUE D'UN ENSEMBLE déf Texte = Séq (Car) DÉFINITION INFORMATIQUE D'UN TYPE type texte = char list ;; Mathématiquement un Alphabet est une séquence de lettres minuscules. Complétez les dénitions ci-dessous. Exercice DÉFINITION MATHÉMATIQUE D'UN ENSEMBLE déf Alphabet = Séq ( . . . . . . . . . . . . . . . . . . . ) 15 DÉFINITION INFORMATIQUE D'UN TYPE type ................ = minuscule ........ ;; 2.2 Dénir un type par énumération On peut dénir un ensemble en énumérant tous ses éléments. On peut dénir un type de la même manière. Exemple 1 Le type des booléens est déni par une énumération nie. DÉFINITION MATHÉMATIQUE DE L'ENSEMBLE déf Bool Bool = {vrai , faux } DÉFINITION INFORMATIQUE DU TYPE Le type bool est déjà déni en type bool = true | false ;; caml Le type énuméré famille correspond à l'ensemble Famille de cartes est déni par l'énumération de ses éléments : Exemple 2 DÉFINITION MATHÉMATIQUE DE L'ENSEMBLE déf Famille F amille = {♥, ♦, ♠, ♣} DÉFINITION INFORMATIQUE DU TYPE type famille = famille Coeur | Carreau | Pique | Trefle | {z } ;; Les noms de constantes symboliques doivent commencer par une Majuscule Exemple 3 Le type Mois est déni par énumération. DÉFINITION MATHÉMATIQUE D'UN ENSEMBLE déf Mois = {Jan, Fev, Mar, Avr, Mai, Juin, Jul, Aou, Sep, Oct, Nov, Dec} DÉFINITION INFORMATIQUE D'UN TYPE type mois = Jan | Fev | Mar | Avr | Mai | Juin | Jul | Aou | Sep | Oct | Nov | Dec ;; Jan, Fev, . . . , Dec sont des constantes symboliques qui n'ont pas de valeur. Il ne faut pas confondre les constantes du type énuméré Mois avec les textes "Jan","Fev",...,"Dec". Remarque importante "Jan" | {z } 6= chaîne Jan |{z} 6= constante symbolique 16 ['J' ;'a' ;'n'] | {z } séquence de caractères 2.3 Construire un produit de types définition (Vecteurs et produit cartésien d'ensembles vs. n-uplets et produit de Les informaticiens et les mathématiciens utilisent un vocabulaire diérent pour parler de la même chose. Il faut connaître les deux terminologies. Les vecteurs des mathématiques sont appelés n-uplets en informatique où n indique la taille du vecteur. types) mathématique le vecteur (π, 0) appartient à R × R le produit cartésien d'ensemble informatique le 2-uplet (3.14159,0.0) est de type float * float le produit de type Z × Minuscule × Bool contient le vecteur (1, int * minuscule * bool 'a', vrai ) accepte le 3-uplet (1,'a',true) Z Les éléments du produit cartésien d'ensembles × Minuscule × Bool sont les vecteurs à 3 composantes constitués d'un entier, d'une lettre minuscule et d'un booléen. Le type correspondant à cet ensemble est le type produit int * minuscule * bool dont les éléments sont des 3-uplets. Exemple 1 : le type Coordonnées Les coordonnées des points du plan sont des couples (x, y) qui appartiennent à R2 . On peut dénir le Coordonnées qui traduira notre intention de modéliser des coordonnées par des couples de réels. DÉFINITION MATHÉMATIQUE D'UN ENSEMBLE déf Coordonnées = R × R DÉFINITION INFORMATIQUE D'UN TYPE type coordonnees = float * float ;; On peut alors dénir et utiliser des variables de type coordonnées mathématique posons c ∈ Coordonnées = (0.5, 2.1) informatique let (c : coordonnees) = (0.5,2.1) ;; l'interpréteur caml répond val c : c = (0.5, 2.1) Ensuite, il est possible de décomposer c an de retrouver ses composantes posons let (x,y) = c ;; (x, y) = c l'interpréteur vaut donc 0.5 y vaut donc 2.1 caml répond val x : float = 0.5 x val y : float = 2.1 17 Une date peut être représentée sous la forme d'un vecteur (j, m, a) où j indique le numéro du jour dans le mois, m est le mois et a l'année. Cette représentation correspond à la dénition mathématique d'un ensemble produit : Exemple 2 : le type Date DÉFINITION MATHÉMATIQUE D'ENSEMBLES déf Jour = {1, . . . , 31} déf Mois = {Jan, Fev, Mar, Avr, Mai, Juin, Jul, Aou, Sep, Oct, Nov, Dec} déf Année = Z déf Date = Jour × Mois × Année DÉFINITION INFORMATIQUE DE TYPES type type type type jour mois annee date = = = = int ;; (* {1,...,31} *) Jan | Fev | Mar | Avr | Mai | Juin | Jul | Aou | Sep | Oct | Nov | Dec int ;; jour * mois * annee ;; ;; Les valeurs de type date sont donc des 3-uplets constitués d'un entier (restreint à {1, ..., 31}), d'un mois dont les valeurs sont des constantes et d'un entier. Voici quelques exemples de valeurs de type date : (31,Dec,-5000) et (1,Jan,2008) sont de type date et respectent les contraintes indiquées en commentaire. (64,Oct,2008) est acceptée par le type date mais ne respecte pas les contraintes indiquées en commentaire. Remarque On a choisi de représenter l'ensemble Jour par le type int en prenant soin d'ajouter en commentaire une contrainte qui précise qu'on considère uniquement les entiers entre 1 et 31. Dans ce cas l'interprète Ocaml considerera tout entier comme un jour acceptable et ne signalera pas d'erreur si on utilise 999 comme un numéro de jour. On aurait pû faire un autre choix et dénir jour comme un type énuméré : DÉFINITION INFORMATIQUE D'UN TYPE type jour = J1 | J2 | J3 | J4 | ... | J29 | J30 | J31 ;; ocaml Dans ce cas peut faire des vérications très précise mais on ne peut plus faire de calculs sur les jours car J1, . . . , J31 ne sont pas des nombres, ce sont justes des noms de constantes. Voici quelques exemples de valeurs de type date correspondant à cette seconde dénition : (J31,Dec,-5000) et (J1,Jan,2008) sont de type date (J64,Oct,2008) n'est pas accepté par le type date Que dire de (J31,Fev,2000) ? Exemple 3 : les types Valeur et Figure On aimerait dénir l'ensemble des cartes à jouer. On distingue l'ensemble des Figures (As, Rois, Dames, Valets) et celui des Valeurs de 7 à 10 pour les diérentes familles possibles ♥, ♦, ♠, ♣. 18 DÉFINITION MATHÉMATIQUE D'ENSEMBLES déf Famille = {♥, ♦, ♠, ♣} déf Tête = {As, Roi, Dame, Valet} déf De7à10 = {7, 8, 9, 10} déf Figure = Tête × Famille As, ♥), (Roi, ♥), (Dame, ♥), (Valet, ♥), . . . , (Valet, ♣)} = {( déf Valeur = De7à10 × Famille = {(7, ♥), . . . , (10, ♥), (7, ♦), . . . , (10, ♦), (7, ♠), . . . , (10, ♠), (7, ♣), . . . , (10, ♣)} DÉFINITION INFORMATIQUE DE TYPES type famille = Coeur | Carreau | Pique | Trefle ;; type tete = As | Roi | Dame | Valet ;; type de7a10 = V7 | V8 | V9 | V10 ;; type figure = tete * famille ;; type valeur = de7a10 * famille ;; 2.4 Construire une somme de types On peut dénir un type comme la réunion de plusieurs types à condition de nommer chacuns des types que l'on souhaite réunir. On dit qu'on fait la somme des types. Exemple 1 On aimerait dénir le type Nombre comme l'union de l'ensemble des entiers et de celui des réels. C'est inacceptable en informatique car les entiers et les réels ne sont pas de même nature. Les ordinateurs doivent distinguer les entiers et les réels car les opérations sur les réels et celles sur les entiers sont eectuées par des parties diérentes du processeur : le calculateur pour les calculs ottants est diérent du calculateur utilisé pour les calculs sur les entiers. Pour réunir les entiers et les réels en un seul type Nombre il faut faire la somme des types à l'aide de constructeurs. On crée un constructeur Entier qui prend en argument une donnée de type Z et construit une donnée de type Nombre . Le constructeur Entier est de type : Z → Nombre. Entier(7) est une donnée de type Nombre . On crée un constructeur Reel qui prend en argument une donnée de type R et construit une donnée de type Nombre . Le constructeur Reel est de type : R → Nombre. Reel(3.14) est une donnée de type Nombre . Les deux constructeurs Entier et Reel construisent des Nombres. Le nom du constructeur permet à l'interprète Ocaml de distinguer si le nombre est un entier ou un réel bien que Entier(7) et Reel(3.14) soient deux données du même type Nombre . Grâce aux constructeurs on a donc réussi à réunir les types entiers et réels tout en préservant leurs diérences. Remarque 19 Les ensembles { Entier(e) | e ∈ Z} et Nombres donc on peut en faire l'union. { Reel(r) | r ∈ R} sont tous deux des ensembles de DÉFINITION MATHÉMATIQUE DE L'ENSEMBLE déf Nombre = { Entier(e) | e ∈ Z} ∪ { Nombre Réel(r) | r ∈ R} DÉFINITION INFORMATIQUE DU TYPE nombre type nombre = Entier of int | Reel of float ;; À retenir Pour réunir des types incompatibles, on utilise un procédé qui consiste à ajouter le nom du type devant ses valeurs. On dénit un nouveau type qui fait la somme des types en utilisant des constructeurs. Principe de construction d'un type somme Exemple 2 On aimerait maintenant dénir le type Carte comme l'union des ensemble Valeur et Figure dénis précédemment. C'est impossible car les éléments de ces ensembles ne sont pas de même nature : et (As, ♥) sont de type diérent : De7à10 × Famille 6= Tête × Famille La seconde composante est de type Famille dans les deux cas mais la première composante est de type entier dans (7, ♥) tandis qu'elle est de type Tête dans (As, ♥). Pour réunir les ensembles Valeur et Figure il faut faire la somme des types à l'aide de constructeurs. On crée un constructeur Valeur qui prend en argument une donnée de type Valeur et construit une donnée de type Carte . Le constructeur Valeur est de type : Valeur → Carte. (7, ♥) est une donnée de type Valeur ; Valeur(7, ♥) est une donnée de type Carte . On crée un constructeur Figure qui prend en argument une donnée de type et construit une donnée de type Carte . Le constructeur Figure est de type : Figure → Carte. (7, ♥) As, ♥) est une donnée de type Figure ; Figure(As, ♥) est une donnée de type Carte . Les deux constructeurs Valeur et Figure construisent des Cartes. Les ensembles { Valeur(v) | v ∈ Valeur} et { Figure(f ) | f ∈ Figure} sont tous deux des ( ensembles de Cartes donc on peut en l'union. DÉFINITION MATHÉMATIQUE D'UN ENSEMBLE déf Carte = { Valeur(v) | v ∈ Valeur} ∪ { Figure(f ) | f ∈ Figure} DÉFINITION INFORMATIQUE D'UN TYPE type carte = Valeur of valeur | Figure of figure ;; On aurait pû dénir le type Carte directement sans dénir les types Valeur et Figure . Voici ce qu'on écrirait dans ce cas. Le deux solutions sont totalement équivalentes. 20 DÉFINITION MATHÉMATIQUE D'UN ENSEMBLE déf Carte = { Valeur(v) | v ∈ {7, . . . , 10} × Famille} ∪ { Figure(f ) | f ∈ Tête × Famille} DÉFINITION INFORMATIQUE D'UN TYPE type carte = Valeur of de7a10 * famille | Figure of tete * famille ;; Exercice a) Dénissez mathématiquement l'ensemble Jeu de carte comme l'ensemble des séquences de cartes puis le type Ocaml correspondant. DÉFINITION MATHÉMATIQUE D'UN ENSEMBLE déf Jeu de carte = . . . . . . . ( . . . . . . . . . . ) DÉFINITION INFORMATIQUE D'UN TYPE type jeu_de_carte = .......... ........ ;; b) Dénissez les-carreaux comme la séquence des cartes de la famille ♦. SPÉCIFICATION MATHÉMATIQUE posons les-carreaux = [Valeur(7, ♣) ; . . . ; Valeur(10, ♣) ; Figure(Valet, ♣) ; RÉALISATION INFORMATIQUE let (les_carreaux : ........................) = [ Valeur(7,Carreau) ; .................................. ; .................................. ; ............(10,Carreau) ; ............(Valet,Carreau) ; Figure(........,Carreau) ; ] ;; ...................................... ; .................................... 21 ... ; Figure(As, ♣)] 22 Chapitre 3 Constructions du langage Ocaml définition On appelle expression les constructions du langage qui ont une valeur. Les constructions qui n'ont pas de valeur sont des instructions. Exemple L'aectation x ← 2 des langages impératifs est une instruction : x ← 2 n'a pas de valeur. x+1 est une expression : x+1 représente une valeur. Remarque Dans les langages fonctionnels purs toutes les constructions ont une valeur, ce sont des expressions. En particulier, l'aectation n'existe pas ! 3.1 Expression conditionnelle Le branchement conditonnel est exprimé par la construction (if cond then expr1 else expr2 ) C'est une expression qui a pour valeur celle de l'expression expr1 ou de l'expression expr2 selon la valeur de la condition booléenne cond. Précisement : expr1 si cond vaut true (if cond then expr1 else expr2 ) = expr si cond vaut false 2 Règle de typage La construction (if ..then ..else ..) doit respecter les contraintes de typage : (if cond | {z } then expr1 else expr2 ) | {z } | {z } ........ | ... {z ... } ... La construction (if cond then expr1 ) sans partie else est interdite car lorsque cond vaut false, l'expression (if cond then expr1 ) n'a pas de valeur. Remarque 3.2 Nommage d'une expression Les mathématiciens utilisent abondamment la construction posons x ∈ T = expression qui permet de donner un nom x à une expression. On utilise alors le nom x plutôt que de réécrire expression (qui peut être complexe ou pénible à écrire). Cette construction existe en Ocaml et se note en anglais : 23 let (x : t) = expression ;; Ocaml. On dit que la dénition Le x de type t ainsi déni peut être utilisé partout dans le programme de x a une portée globale, c'est-à-dire qu'elle porte sur tout le programme. Exemple SPÉCIFICATION MATHÉMATIQUE RÉALISATION INFORMATIQUE posons π ∈ R = 3, 141592653589 let (pi:float) = 3.141592653589 ;; Restriction de la portée d'une dénition Lorsqu'on veut utiliser la valeur de x uniquement dans une expression on peut limiter la portée de la dénition de x. On utilise pour cela la construction : posons qui se note en x = expression Ocaml : dans expr où expr est une expression utilisant x let x = expression in expr ;; Principe d'évaluation suivante : La construction let ... in ... est une expression qui s'évalue de la manière 1. on commence par évaluer l'expression, 2. on remplace dans expr toutes les occurrences de x par la valeur de expression, 3. on évalue expr. Exemple let x = max (3,4) in x + max (5, x) est équivalent à max (3,4) + max (5, max (3,4)) Règle de typage La construction let ... in ... doit respecter les constraintes de type : (let |{z} x = expression in expr utilisant x) | {z } | {z } ... | ... .... {z } .... Cette construction a l'avantage de n'évaluer qu'une fois l'expression expr. Le nom x introduit est local à la construction let ... in ..., c'est-à-dire que x n'est pas connu en dehors de la partie expr. On dit que la portée du nom x se limite à la partie expr. Remarque 1 Remarque 2 Il est possible d'imbriquer les expressions let ... in ... et d'eectuer plusieurs nommages simultanément (let x1 = expr1 and x2 = expr2 in ...). La construction let utilisée de la manière suivante : let (x,y) = v ;; permet de décomposer un vecteur v en chacunes de ses composantes x, y, comme dans l'exemple du type Coordonnées du 2.3 et l'exercice sur les relations entre intervalles. Remarque 3 24 3.3 Expression de ltrage Le ltrage permet d'associer des valeurs à des motifs reconnaissables. Pour réaliser un ltrage en on utilise la construction (match .. with ..) que l'on peut traduire par (reconnaître .. parmi ..). Ocaml Notation et principe d'évaluation (match expr with | motif 1 -> expr1 | ... | motif n -> exprn ) Cette construction s'évalue de la manière suivante : on compare la valeur de l'expression expr avec le premier motif motif 1 , si ce motif reconnaît expr le résultat de la construction (match .. with ..) est la valeur de l'expression expr1 ; sinon on passe au motif suivant. Si aucun motif n'a reconnu la valeur expr, l'évaluation échoue et provoque une erreur. Exemple 1 Le ltrage permet d'associer le nombre de jour à une variable m de type Mois (voir 2.2). Chaque motif essaie de reconnaître la valeur m et rend le nombre de jour correspondant. Remarquez qu'on peut regrouper les motifs qui rendent le même résultat. (match | Fev | Avr | Jan ) m with -> 28 | Juin | Sep -> 30 | Fev | Mar | Mai | Jul | Aou | Oct | Dec -> 31 Vous constatez que le programmeur a oublié le mois de novembre. L'interprète toutes les valeurs possibles du type mois ; il découvre qu'il manque le mois de novembre et ache le message suivant1 : Remarque 1 Ocaml détecte cet oubli : il vérie que les motifs couvrent Warning: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: Nov La vérication de l'exhaustivité du ltrage permet à programmeur de la corriger. Ocaml de détecter une erreur et permet au Vous constatez que le programmeur a mis deux fois le mois de février et donne deux valeurs diérentes pour Fev : 28 et 31. L'interprète Ocaml détecte cette incohérence, souligne le motif qui pose probléme (le second Fev) et ache le message suivant2 : Remarque 2 Warning: this match case is unused. La vérication de l'exhaustivité du ltrage permet à programmeur de la corriger. Ocaml de détecter une erreur et permet au À retenir Lorsqu'on utilise une expression de ltrage, il faut qu'elle soit exhaustive, c'est-àdire qu'elle comporte un motif pour chaque valeur possible de expr. Dans le cas contraire, l'interprète Ocaml signalera une erreur. L'expression de ltrage suivante associe à la variable c de type Carte (voir page 19) un nombre de points correspondant à son rang. Exemple 2 1 (Traduction) Attention : cette reconnaissance de motif n'est pas complète. Voici un exemple de valeur qui n'est pas reconnue : Nov 2 (Traduction) Attention : ce motif n'est jamais utilisé. 25 (match c with | Valeur(v,f) -> v | Figure(Valet,f) -> 11 | Figure(Dame,f) -> 12 | Figure(Roi,f) -> 13 | Figure(As,f) -> 14 ) Exemple 3 minuscule. L'expression de ltrage suivante vaut vrai si et seulement si la variable l est une voyelle (match l with | 'a' | 'e' | 'i' | 'o' | 'u' | 'y' -> true | _ -> false ) Le motif - est le motif universel. Il reconnaît toutes les expressions et les accepte sans condition. Il faut donc toujours le placer en dernier. D'autre part, lorsqu'on utilise -, le ltrage est forcément exhaustif et cela empêche caml de détecter des oublis du programmeur. Il faut donc utiliser - avec précaution et parcimonie ; uniquement quand l'énumération est très très longue ou impossible. Remarque Règle de typage La construction (match .. with ..) doit respecter les contraintes de typage : T z }| { match expr with | motif 1 -> expr1 | {z } | {z } 0 T T | ... | motif n -> exprn | {z } | {z } T est de type T 0 T0 3.4 Expression de ltrage avec condition La construction motif when condition -> résultat permet d'ajouter une condition à une reconnaissance par motif. Notation et principe d'évaluation (match expression with | motif 1 when condition1 -> expr1 | ... | motif n when conditionn -> exprn ) Une branche du ltrage match expression with sera prise uniquement sont réunies : 1. L'expression est reconnue par le motif 2. L'évaluation de la condition associée donne vrai 26 quand les deux conditions L'expression de ltrage ci-dessous permet de calculer le nombre de point correspondant à une variable c de type Carte en tenant compte de la variable atout de type Famille (voir page 19). Exemple 4 Implantation à l'aide de motifs avec condition match c with | Valeur(9,f) when f = atout -> 15 | Figure(Valet,f) when f = atout -> 30 | Valeur(v,_) -> v | Figure(Valet,_) -> 11 | Figure(Dame,_) -> 12 | Figure(Roi,_) -> 13 | Figure(As,_) -> 14 ;; Dans une expression de ltrage on peut avoir des motifs avec et des motifs sans condition. On ajoute des conditions au motifs uniquement lorsque c'est nécessaire. Remarque Exemple 5 dénis par : L'expression de ltrage ci-dessous doit donner le Signe de l'entier x parmi les trois cas possibles DÉFINITION MATHÉMATIQUE D'UN ENSEMBLE déf Signe = {Negatif, . . . . . . . . , Positif} DÉFINITION INFORMATIQUE D'UN TYPE type signe = .............. | Nul | Positif ;; Implantation incorrecte match x with | x when x>0 -> Positif | x when x<0 -> Negatif ;; Remarque Il est important que l'expression de ltrage soit exhaustive. Ici, le programmeur a oublié un cas. Si x = 0 l'évaluation de l'expression de ltrage produira une erreur : Exception: Match_failure. qui signie erreur de ltrage. Implantation correcte match x with | x when x>0 -> Positif | x when x<0 -> Negatif | _ -> ...... ;; 27 3.5 Filtrage avec condition versus conditionnelles imbriquées Le ltrage avec conditions permet de réaliser des if...then...else... imbriqués. Il n'y a pas une solution qui soit systématiquement meilleure que l'autre. Il faut choisir celle qui est la plus élégante. On reprend l'exemple du signe d'un entier x ∈ Z et on souhaite écrire une fonction signe-de qui donne le signe de x. Exemple SPÉCIFICATION MATHÉMATIQUE Prol signe-de : Z → Signe Sémantique : signe-de (x) est le signe de l'entier x Exemples 1. signe-de (0) = Nul 2. signe-de (1) = Positif 3. signe-de (-1) = Negatif RÉALISATION INFORMATIQUE Implantation 1 à l'aide de if...then...else... imbriqués let (signe-de : int -> signe) = function x -> if x<0 then ............... else if ...... then Positif else (* x=0 *) ...... ;; Implantation 2 à l'aide d'un ltrage avec condition let (signe-de : int -> signe) = function x -> match x with | x when x<0 -> ............... | x when ...... -> Positif | x when x=0 -> ...... ;; Remarque La partie encadrée est inutile en caml et on peut se contenter d'écrire : Implantation 2' : autre notation acceptée par caml let (signe-de : int -> signe) = function | x when x<0 -> ............... | x when ...... -> Positif 28 ;; | x when x=0 -> ...... Remarquez que la partie x -> match x with est optionnelle. L'implantation 2' se lit de la manière suivante : signe-de est une fonction qui donne Negatif quand x < 0, qui donne Positif quand x > 0 et Nul quand x = 0. 29 30 Chapitre 4 Dénition de fonctions En informatique la dénition d'une fonction doit comporter deux parties : 1. une spécication c'est-à-dire une description mathématique de la fonction présentée ainsi : SPÉCIFICATION MATHÉMATIQUE Prol nom de la fonction : type de la fonction Sémantique : rôle de la fonction 2. une réalisation de la fonction dans un langage de programmation présentée ainsi : RÉALISATION INFORMATIQUE Algorithme : l'algorithme décrit le principe utilisé pour réaliser la fonction Implantation (en caml dans ce cours) let (nom de la fonction : type de la fonction ) = function ... Exemple 1 : maximum de deux entiers SPÉCIFICATION MATHÉMATIQUE (fournie par l'utilisateur au programmeur) Prol max2 : Z × Z → Z Sémantique : max2 (x, y) est le plus grand des entiers x et y Exemple : max2 (0, 1) = 1 Propriétés 1. 2. Z ∀x ∈ Z, max2 (x, −x) = |x| ∀x ∈ , max2 (x, x) = x 31 RÉALISATION INFORMATIQUE Algorithme : max2 (x, y) = (mise au point par le programmeur de manière à respecter la spécication de l'utilisateur) x si x>y y si x < y x (ou y) si x = y Implantation en caml let (max2 : int * int -> int) = function (x , y) -> if (x>y) then x else y ;; 4.1 La spécication : un contrat entre l'utilisateur et le programmeur En informatique, on distingue deux parties dans la dénition d'une fonction : 1. la spécication mathématique de la fonction. Elle décrit : les conditions d'utilisations de la fonction (son prol), c'est-à-dire quels paramètres il faut lui donner : combien et de quels types, quels résultats elle rend : combien et de quels types ; ce que fait la fonction (sa sémantique), c'est-à-dire quel résultat elle rend et les propriétés de ce résultat (les exemples et les propriétés). 2. la réalisation informatique de la fonction. Elle décrit le principe (l'algorithme) qui permet de produire le résultat attendu et fournit une version de l'algorithme écrit un langage de programmation (l'implantation). La spécication mathématique est destinée à l'utilisateur de la fonction qui veut savoir comment il l'utiliser. La réalisation informatique est faîte par le programmeur qui doit trouver et implanter un algorithme qui respecte la spécication informatique. La spécication informatique joue le rôle d'un contrat entre un client (l'utilisateur ) et le fournisseur (le programmeur ). Exemple 2 : on réutilise le type Mois déni page 16. Imaginons qu'un utilisateur ait besoin d'une fonction juste-avant qui prend un couple de Mois (m1 , m2 ) et qui vaut vrai si le mois m1 est exactement le mois avant m2 . On convient que le mois de décembre est avant le mois de janvier de l'année suivante. L'utilisateur s'adresse à vous, programmeur caml. Il vous donne la spécication et vous devez réaliser la fonction. SPÉCIFICATION MATHÉMATIQUE Prol juste-avant : Mois × Mois → Bool Sémantique : juste-avant (m1 , m2 ) est vraie si et seulement si m1 est le mois qui précède m2 Exemple : Les exemples servent à préciser le résultat attendu dans les cas particuliers, comme : juste-avant (Dec, Jan) = vrai Propriété ∀m ∈ Mois, juste-avant (m, m) = faux 32 RÉALISATION INFORMATIQUE Algorithme c'est la description du principe qui permet d'arriver au résultat : On énumère l'ensemble des . . . . couples (m1 , m2 ) qui satisfont la relation est juste avant : Jan, Fev), (Fev, Mar), {( Dec, Jan)} ..., ( Implantation c'est la traduction du principe dans un langage de programmation let (juste_avant : mois * mois -> ........) = function ( m1 , m2 ) -> match (m1,m2) with | (Jan,Fev) | .................. | .................. | .................. | .................... | .................... | .................... | .................... | (......,......) | (......,......) ;; | (......,......) | (Dec,Jan) -> ........ | _ -> .......... 4.2 Le programmeur est aussi l'utilisateur de ses propres fonctions Souvent les programmeurs travaillent en équipe : ils utilisent les fonctions des autres et pour cela ils lisent les spécications an de savoir comment bien utiliser la fonction d'un autre ou bien ils écrivent la spécication d'une fonction et c'est un autre programmeur qui la réalisera. Un programmeur est aussi l'utilisateur de ses propres fonctions et la spécication est utile pour se souvenir rapidement de ce que fait une fonction qu'il a écrite des mois ou des années auparavant. Dans tous ces cas il est utile d'écrire la spécication pour se souvenir de la bonne manière d'utiliser une fonction. Exemple 3 : on réutilise le type Nombre déni page 19. Imaginons qu'en tant qu'utilisateur vous ayez besoin d'une fonction qui prend en paramètre deux Nombre et les additionne. On commence par rédiger la spécication an de décire le rôle de la fonction avant de la réaliser. SPÉCIFICATION MATHÉMATIQUE Prol addition : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . → Nombre Sémantique : addition (n1 , n2 ) est le nombre Entier ou Reel correspondant à l'addition la plus précise possible des valeurs représentées par n1 et n2 Exemples : 1. addition (Entier(e1 ), Entier(e2 )) = Entier(e1 + e2 ) 2. addition (Entier(e), Reel(r)) = Reel( . . . . . . . . . . . . . . . . . . . . . (e) +. r) | {z on convertit e en } ..... RÉALISATION INFORMATIQUE Algorithme : Selon le type de n1 et de celui n2 on choisit l'opérateur d'addition à utiliser parmi 33 Prol (+) : int → int → int Prol (+.) : float → float → float Lorsque c'est nécessaire on convertit un entier en réel grâce à la fonction Prol float-of-int : int → float Cette convertion ne perd pas de précision car Z . . . R. Implantation let (addition : nombre * ............ -> ............) = function (n1 , n2) -> match (n1,n2) with | (Entier(e1), Entier(e2)) -> ............( e1 + e2 ) ;; | (........(r1) , Réel(r2)) -> ........( r1 +. r2 ) | (............(e), Réel(r)) -> ........( (float_of_int e) .... r ) | (........(r) , Entier(e)) -> ........( r +. ................................ ) 4.3 Dénition de fonctions partielles = fonctions avec condition Une fonction partielle sur les entiers est une fonction qui n'est pas dénie pour tous les entiers possibles. C'est par exemple le cas de la division euclidienne de a par b qui est dénie uniquement b > 0. La construction when permet de signaler dans l'implantation de la fonction div que c'est une fonction partielle. Exemple 5 La division euclidienne d'un entier a par un entier b doit donner un quotient q et un reste r tels que : a = b × q + r avec q, r ∈ N et r < b. On dit que la fonction div est partielle puisqu'elle n'est pas dénie pour tous les entiers b possibles. Elle n'a de sens que pour b > 0. DÉFINITION MATHÉMATIQUE D'UN ENSEMBLE déf N∗ = {n ∈ Z | n >0 } DÉFINITION INFORMATIQUE D'UN TYPE type nat_positif = int (* >0 *) SPÉCIFICATION MATHÉMATIQUE Prol div : Z × N∗ → N × N Sémantique : div(a, b) est le couple (quotient,reste) de la division euclidienne de a par b 34 Exemples 1. 2. 3. div(5, 3) = (1, 2) div(5, 0) = erreur : la fonction n'est pas dénie dans le cas b = 0 div(5, −3) = erreur : la fonction n'est pas dénie dans le cas b < 0 La construction function .. when condition permet de préciser que la fonction est dénie uniquement lorsque b > 0. La condition b > 0 correspond à la condition encadré de l'ensemble N∗ et du type nat_positif. RÉALISATION INFORMATIQUE Implantation let(div: int * nat_positif -> nat * nat) = function (a,b) when b>0 -> let q = a/b and r = a mod b in (q,r) ;; L'utilisation de la fonction div avec b = −3 ou b = 0 provoque une erreur Match_failure. Ce n'est pas une faute du programmeur ; au contraire, c'est voulu et le programmeur a parfaitement fait son travail puisque la fonction div est conforme à la spécication qui prévenait dans le prol de div et dans les exemples qu'il ne fallait pas utiliser div avec un b ≤ 0. Remarque 4.4 Respectez la spécication laisse malgré tout de la liberté La spécication est un contrat entre l'utilisateur et le programmeur. Pour que l'utilisateur ne soit pas surpris par les résultats de votre implantation il faut veiller à bien respectez la spécication. Exemple 6 : Réalisation du prédicat est-voyelle par ltrage sur le type énuméré des caractères Imaginons qu'en tant que programmeur vous ayez besoin d'un prédicat est-voyelle qui indique si une lettre minuscule est une voyelle. Spéciez puis réalisez le prédicat est-voyelle . définition (prédicat) Un prédicat est une fonction qui rend un booléen. du prédicat est-voyelle Prol est-voyelle : Minuscule → . . . . . . . . Sémantique : est-voyelle (l) est . . . . . . . si et seulement si l ∈ {'a', 'e', 'i', 'o', 'u', 'y'} SPÉCIFICATION MATHÉMATIQUE Exemples 1. est-voyelle ('a') = . . . . . . . . 2. est-voyelle ( . . . . . . ) = faux 3. est-voyelle ('A') n'est pas prévu par le type Minuscule Dans cette spécication le comportement de la fonction est-voyelle n'est déni que pour les minuscules, il n'est pas précisé pour les lettres majuscules. 35 Conclusion Le programmeur est donc libre de choisir le comportement de la fonction est-voyelle pour les majuscules : il peut rendre soit vrai , soit faux . Mais il peut aussi choisir de ne pas dénir la fonction pour les lettres majuscules et dans ce cas la fonction retournera Match_failure. Plusieurs implantations possibles Nous allons examiner des implantations diérentes qui ne rendent pas les mêmes résultats et qui pourtant respectent toutes cla spécication. Avant cela examinons comment sont dénis les caractères. DÉFINITION MATHÉMATIQUE DE L'ENSEMBLE des caractères, par énumération nie déf Car = {'a', . . . , 'z', 'A', . . . , 'Z', '@', '#', '$', . . . , '%'} DÉFINITION INFORMATIQUE DU TYPE type char = 'a' | . . . 'z' | 'A' | . . . | 'Z' | '@' | '#' | '$' | . . . | '%' ;; Le type char est prédéni en caml sous la forme d'un type énuméré. Puisque le type char est un type énuméré on peut utiliser le ltrage match ... with... sur les caractères et caml indiquera si on a oublié des cas. On peut donc dénir la fonction par énumération. RÉALISATION INFORMATIQUE Algorithme : On énumère les lettres minuscules qui satisfont la condition être une voyelle. Implantation 1 let (est_voyelle : minuscule -> bool) = function l -> match l with | 'a' | 'e' | 'i' | 'o' | 'u' | 'y' -> true | _ -> false ;; Implantation 1' : autre notation acceptée par caml let (est_voyelle : minuscule -> bool) = function | 'a' | 'e' | 'i' | 'o' | 'u' | 'y' -> true | _ -> false ;; Remarquez que la partie l -> match l with est optionnelle. L'implantation 1' se lit de la manière suivante : est-voyelle est une fonction qui à chaque lettre 'a', 'e', 'i', 'o', 'u', 'y' associe true et qui associe false aux autres lettres (y compris les voyelles en majuscule). Les implantations 1 et 10 ci-dessus respectent la spécication puisqu'elles rendent vrai pour les voyelles en minuscule. On propose maintenant une autre implantation. 36 Exercice 1 L'implantation 2 ci-dessous respecte-elle la spécication de est-voyelle ? Implantation 2 let (est_voyelle : char -> bool) = function | 'a' | 'e' | 'i' | 'o' | 'u' | 'y' | 'A' | 'E' | 'I' | 'O' | 'U' | 'Y' -> true | _ -> false ;; . . . . . . puisque la spécication ne . . . . . . . . . . . . pas ce qu'il faut . . . . . . . . . . . . . . . . comme résultat pour les lettres . . . . . . . . . . . . . . . . . . . donc le programmeur est libre de . . . . . . . . . . . la valeur à rendre pour les voyelles en . . . . . . . . . . . . . . . . . . . Exercice 2 Proposez une nouvelle spécication plus précise qui correspond à l'implantation 2. SPÉCIFICATION MATHÉMATIQUE du prédicat est-voyelle est-voyelle : . . . . . . . . . . . → . . . . . . . . Prol Sémantique : est-voyelle (l) est . . . . . . . si et seulement si l ∈ {'a', 'e', 'i', 'o', 'u', 'y'} . . { . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . } Exemples : 1. est-voyelle ('a') = . . . . . . . . = est-voyelle ('A') 2. est-voyelle ('z') = . . . . . . . . = est-voyelle ('Z') Propriété ∀l ∈ . . . . . . . . . . . , est-voyelle (l) . . . est-voyelle (majuscule( . )) 37