1/30 Chapitre 0 : Le langage Caml Programmation impérative versus fonctionnelle Prog. impérative séquences d’instructions ; notion d’état du programme ; boucles for et while essentielles. les processeurs sont de nature impérative : exécutions d’instructions données par « op codes ». état du programme : contenu de la mémoire à chaque instant. Python, C, Assembleur, Langage machine : plus ou moins haut niveaux, mais tous impératifs. 2/30 Programmation impérative versus fonctionnelle Prog. fonctionnelle autre paradigme de programmation ; un programme est une fonction mathématique ; exécution du programme : évaluation de la fonction ; Eviter la notion d’état, d’effet de bord : un calcul donne toujours le même résultat (c.ex : fonction de tri en Python) la récursivité (appel d’une fonction à elle même) remplace les boucles. 3/30 Exemple : la factorielle Factorielle impérative Fonction fact(n) f ← 1; pour i allant de 1 à n faire faire f ←f ×i fin Renvoyer f Factorielle fonctionnelle Fonction fact(n) si n ≥ 0 alors Renvoyer 1 sinon Renvoyer n × fact(n − 1) fin 4/30 Python versus Caml Python Langage impératif, permettant l’usage de la récursivité. Caml Langage fonctionnel, permettant la programmation impérative. 5/30 Introduction à Caml Un langage fortement typé ; présentation de l’interpréteur : 4+1 ;; Caml : fortement typé. un calcul Caml termine par ;; Caml procède (avant l’évaluation) par une analyse de type. Mélange des genres interdit ! notion de polymorphisme (exemple : max). avantages/inconvénients plus dur d’écrire des choses fausses ; un peu plus long à écrire que Python. 6/30 Types simples Unit type unit équivalent du None de Python. Une seule valeur : (). # () ;; - : unit = () Entiers type int sur 64 bits, plage de valeurs [[−262 , 262 − 1]]. opérateurs usuels : +, *, -, / (division entière) et mod (modulo). # # - 7/30 2*16 ;; : int = 32 58 mod 14 ;; : int = 2 Types simples Flottants type float ; semblables à ceux de Python ; opérateurs simples : les mêmes que pour les entiers (sauf mod qui n’a pas d’équivalent), mais suivis d’un point : +., /., -., *. ; fonctions usuelles (cos, sin, exp, atan...) définies sur les flottants ; exponentiation (**). # # # - 8/30 2.0 *. 8.9 ;; : float = 17.8 2.0 ** 8.9 ;; : float = 477.712891667 cos 5. ;; : float = 0.283662185463 Types simples Pas de mélanges ! # 2 * 3.0 ;; Toplevel input: >2 * 3.0 ;; > ^^^ This expression has type float, but is used with type int. # 2 ** 5 ;; Toplevel input: >2 ** 5 ;; >^ This expression has type int, but is used with type float. 9/30 Types simples Booléens type bool ; deux constantes : true et false ; opérateurs : && (et logique), || (ou logique, la barre s’obtient avec Alt gr + 6) et not (non logique). # # # - true && false ;; : bool = false false || true ;; : bool = true not true ;; : bool = false paresseux, comme en Python : # # 10/30 false && 1/0>0 ;; : bool = false true || 1/0>0 ;; : bool = true Déclarations Déclaration « globale » let x= ... ;; pour déclarer une variable. plutôt une constante... # let x = 4 ;; x : int = 4 Déclaration « locale » let x= ... in ... ;; pour déclarer une variable localement. si x déja liée, valeur précédente oubliée (temporairement) ; affectation locale à ce qui suit in ; # # - 11/30 let x= 5.**0.25 in x +. x *. x +. x ** 3. ;; : float = 7.0751182836 x ;; : int = 4 Déclarations Déclaration « simultanée » let x= ... and y= ... ;; pour déclarer deux variables simultanément ; compatible avec in ; # x y # - let x=0 : int = : int = let x=0 : int = and y=1 ;; 0 1 and y=1 in x+y ;; 1 ne pas confondre locale et simultanée. # let x=0 and y=x+2 in x+y ;; Toplevel input: >let x=0 and y=x+2 in x+y ;; > ^ The value identifier x is unbound. 12/30 Déclarations : références Références variables Caml : liaison d’un nom et d’une valeur ; référence : « pointeur » vers une case mémoire dont on peut lire et écrire le contenu ; la « valeur » de la référence est une adresse mémoire (fixée) la valeur « pointée » par la référence est modifiable syntaxe : ref valeur pour créer une référence pointant initialement vers valeur. type t ref, où t est le type de la valeur. typique de la programmation impérative ! # let r= ref 0 ;; r : int ref = ref 0 13/30 Déclarations : références Déférencement, modification valeur pointée par une référence !r ; modifier la valeur : r := x. # x # # - 14/30 let x= ref 0 ;; : int ref = ref 0 x:= !x + 1 ;; : unit = () !x ;; : int = 1 Types plus complexes Tuples n-uplet type : produit cartésien des types syntaxe : parenthèses facultatives et virgules # (true, 0, atan 1.0) ;; - : bool * int * float = true, 0, 0.785398163397 déconstruction : let a,b,... = t # let a,b=(0, 1.0) ;; a : int = 0 b : float = 1.0 fst et snd : renvoie première et deuxième composante d’un couple. # # 15/30 fst (1, 5.0) ;; : int = 1 snd (4, true) ;; : bool = true Types plus complexes Tableaux taille fixée à la création : immuable ; homogène ! type t vect où t est le type des éléments. # # - [|5; 0; 7|] ;; : int vect = [|5; 0; 7|] [|(2,1) ; (5,7)|] ;; : (int * int) vect = [|2, 1; 5, 7|] si n la taille, t.(0), ..., t.(n-1) : accès aux éléments ; modification : t.(i) <- x # t # # - let t = [|0; 5; 7|] ;; : int vect = [|0; 5; 7|] t.(0) <- 2 ;; : unit = () t ;; : int vect = [|2; 5; 7|] programmation impérative ! 16/30 Types plus complexes Chaînes de caractères type string très similaire à des char vect accès/modification : s.[i] attention : char 6= string. # s # # # - 17/30 let s = "abc" ;; : string = "abc" s.[0] ;; : char = `a` s.[0] <- `d` ;; : unit = () s ;; : string = "dbc" Fonctions Quelques exemples # # # # - 18/30 int_of_float ;; : float -> int = <fun> int_of_float (3.5) ;; : int = 3 fst ;; : 'a * 'b -> 'a = <fun> fst (true, 5.4) ;; : bool = true Fonctions Quelques exemples # # # # - int_of_float ;; : float -> int = <fun> int_of_float (3.5) ;; : int = 3 fst ;; : 'a * 'b -> 'a = <fun> fst (true, 5.4) ;; : bool = true Fonctions une fonction est une valeur type : t1 -> t2 ; 18/30 Fonctions à un seul argument. Appel Syntaxe function variable -> expression types de la variable et de l’expression détectés automatiquement # function x -> x+1 ;; - : int -> int = <fun> Appel comme en mathématiques : f (x) ; en fait les parenthèses sont facultatives : f x. x de type t1 et f de type t1 -> t2 alors f x de type t2. polymorphisme ! Exemples # # 19/30 (function x -> x +. 1.) 2. ;; : float = 3.0 let f = function x -> x+1 in f 5 ;; : int = 6 Fonctions à un seul argument + liaison Syntaxe Pour déclarer et lier une fonction à une variable ; let f x = expression 20/30 Fonctions à un seul argument + liaison Syntaxe Pour déclarer et lier une fonction à une variable ; let f x = expression Exemple 1 # f # - 20/30 let f x = x+1 ;; : int -> int = <fun> f 5 ;; : int = 6 Fonctions à un seul argument + liaison Syntaxe Pour déclarer et lier une fonction à une variable ; let f x = expression Exemple 1 # f # - let f x = x+1 ;; : int -> int = <fun> f 5 ;; : int = 6 Exemple 2 : fonction sur un couple # f # - 20/30 let f : int f (0, : int (x,y) = x+y ;; * int -> int = <fun> 2) ;; = 2 Fonctions à un seul argument + liaison Exemple 3 : polymorphisme # f # - 21/30 let f (x,y) = (y, x) ;; : 'a * 'b -> 'b * 'a = <fun> f (2, 3.0) ;; : float * int = 3.0, 2 Fonctions à un seul argument + liaison Exemple 3 : polymorphisme # f # - let f (x,y) = (y, x) ;; : 'a * 'b -> 'b * 'a = <fun> f (2, 3.0) ;; : float * int = 3.0, 2 Exemple 4 : avec déclaration locale # f # - 21/30 let f x = let y= exp x in (y+. 1.0/. y)/. 2. ;; : float -> float = <fun> f 1.0 ;; : float = 1.54308063482 Fonctions à un seul argument + liaison Exemple 3 : polymorphisme # f # - let f (x,y) = (y, x) ;; : 'a * 'b -> 'b * 'a = <fun> f (2, 3.0) ;; : float * int = 3.0, 2 Exemple 4 : avec déclaration locale # f # - let f x = let y= exp x in (y+. 1.0/. y)/. 2. ;; : float -> float = <fun> f 1.0 ;; : float = 1.54308063482 Exemple 5 : déclaration simultanée # let ch x and sh ch : float sh : float 21/30 = let y= exp x in (y+. 1.0/. y)/. 2. x = let y= exp x in (y-. 1.0/. y)/. 2.;; -> float = <fun> -> float = <fun> Notion de curryfication Bijetion naturelle F(E1 , E2 ) : applications de E1 dans E2 ; F(E × F , G) : applications de E × F dans G ; F(E , F(F , G)) : applications de E dans F(F , G) ; 22/30 Notion de curryfication 22/30 Bijetion naturelle F(E1 , E2 ) : applications de E1 dans E2 ; F(E × F , G) : applications de E × F dans G ; F(E , F(F , G)) : applications de E dans F(F , G) ; bijection naturelle ! ϕ : F(E × F , G) → f 7−→ F(E , F(F , G)) x→ 7 (y 7→ f (x , y )) Forme curryfiée / non-curryfiée f ∈ F(E × F , G) : forme non curryfiée ; f ∈ F(E , F(F , G)) : forme curryfiée ; intérêt des formes curryfiées : fonctions partielles ! se généralise à F(E1 × · · · × En , G) Type et appels d’une fonction curryfiée Type t_1 * t_2 -> t : non curryfiée t_1 -> (t_2 -> t) : curryfiée Caml omet les parenthèses : t_1 -> t_2 -> t. 23/30 Type et appels d’une fonction curryfiée Type t_1 * t_2 -> t : non curryfiée t_1 -> (t_2 -> t) : curryfiée Caml omet les parenthèses : t_1 -> t_2 -> t. Appel d’une fonction curryfiée si f : t1 -> t2 -> t et x de type t1, f x a le type t2 -> t ; si y de type t2, (f x) y a le type t ; parenthèses inutiles, priorité à la fonction : f x y généralisation : f x1 x2 x3 ... xn 23/30 Exemples Caml Exemple 1 : max # # # - 24/30 max ;; : 'a -> 'a -> 'a = <fun> max 20 ;; : int -> int = <fun> max 20 58 ;; : int = 58 Exemples Caml Exemple 1 : max # # # - max ;; : 'a -> 'a -> 'a = <fun> max 20 ;; : int -> int = <fun> max 20 58 ;; : int = 58 Exemple 2 : make_vect # # - 24/30 make_vect ;; : int -> 'a -> 'a vect = <fun> make_vect 5 0 ;; : int vect = [|0; 0; 0; 0; 0|] Exemples Caml Exemple 1 : max # # # - max ;; : 'a -> 'a -> 'a = <fun> max 20 ;; : int -> int = <fun> max 20 58 ;; : int = 58 Exemple 2 : make_vect # # - make_vect ;; : int -> 'a -> 'a vect = <fun> make_vect 5 0 ;; : int vect = [|0; 0; 0; 0; 0|] Exemple 3 : sub_vect #sub_vect ;; - : 'a vect -> int -> int -> 'a vect = <fun> #sub_vect [| 1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0 |] 2 4 ;; - : float vect = [|3.0; 4.0; 5.0; 6.0|] 24/30 Création de fonctions curryfiées Méthode 1 : function # function x -> (function y -> x+y) ;; - : int -> int -> int = <fun> 25/30 Création de fonctions curryfiées Méthode 1 : function # function x -> (function y -> x+y) ;; - : int -> int -> int = <fun> Méthode 2 : fun # # - 25/30 fun x y -> x+y ;; : int -> int -> int = <fun> (fun x y -> x+y) 1 6 ;; : int = 7 Création de fonctions curryfiées Méthode 1 : function # function x -> (function y -> x+y) ;; - : int -> int -> int = <fun> Méthode 2 : fun # # - fun x y -> x+y ;; : int -> int -> int = <fun> (fun x y -> x+y) 1 6 ;; : int = 7 Méthode 3 avec liaison # let somme x y = x+y ;; somme : int -> int -> int = <fun> # somme 1 6 ;; - : int = 7 25/30 Création de fonctions curryfiées Méthode 1 : function # function x -> (function y -> x+y) ;; - : int -> int -> int = <fun> Méthode 2 : fun # # - fun x y -> x+y ;; : int -> int -> int = <fun> (fun x y -> x+y) 1 6 ;; : int = 7 Méthode 3 avec liaison # let somme x y = x+y ;; somme : int -> int -> int = <fun> # somme 1 6 ;; - : int = 7 Généralisation Déclaration + liaison : let f x1 x2 ... xn = expression 25/30 Expressions conditionnelles en Caml if then else if cond then a else b cond expression booléenne ; a et b expressions de même type type de l’expression = type commun à a et b. Exemple # if true then 1 else 0 ;; - : int = 1 # 1+(if true then 1 else 0) ;; - : int = 2 # if true then 1.0 else 2 ;; Toplevel input: >if true then 1.0 else 2 ;; > ^ This expression has type int, but is used with type float. 26/30 Expressions conditionnelles en Caml Quelques subtilités pas de else équivalent à else () # if true then print_string "c'est vrai !" ;; c'est vrai !- : unit = () 27/30 Expressions conditionnelles en Caml Quelques subtilités pas de else équivalent à else () # if true then print_string "c'est vrai !" ;; c'est vrai !- : unit = () en Caml, séquence d’instructions séparées par des points-virgules ; une seule instruction dans les blocs if, else ou utilisation de begin ... end. # if true then x:=1 ; print_string "Exécuté ?" ;; Exécuté ?- : unit = () # if false then x:=1 ; print_string "Exécuté ?" ;; Exécuté ?- : unit = () # if false then begin x:=1 ; print_string "Exécuté ?" end ;; - : unit = () 27/30 Boucles boucle for for i = i1 to i2 do instructions done. i prend les valeurs de i1 à i2 (inclus) ; si i2 < i1 pas d’exécution ; corps de boucle : instructions, séparées par des point-virgules, de type unit type de la boucle : unit. pas de modification du compteur de boucle ! variante : for i = i1 downto i2 do instructions done 28/30 Boucles Exemple de boucle for : factorielle let fact n= let y=ref 1 in for i=1 to n do y:= !y * i done ; !y ;; 29/30 Boucles boucle while similaire : while cond do instructions done mêmes restrictions Exemple de boucle while : Euclide let pgcd a b= let x=ref a and y=ref b in while !y > 0 do let r= !x mod !y in x:= !y ; y:= r done ; !x ;; 30/30