Module programmation: le langage CAML.


Partie I
Un survol du langage




Déclarations


#let une_constante = 1;;
une_constante : int = 1
#let une_constante = 3.4 in 
   une_constante+.1.2;;
- : float = 4.6
#let carré = function x -> x*x;;
carré : int -> int = <fun>
#let carré (x) = x*x;;
carré : int -> int = <fun>
#let carré x = x*x;;
carré : int -> int = <fun>
#carré (25);;
- : int = 625
#carré 36;;
- : int = 1296
#let rec fact = function n ->
   if n <= 0 then 1 else n*fact(n-1);;
fact : int -> int = <fun>
#let une_variable = ref true;;
une_variable : bool ref = ref true
#une_variable := false;;
- : unit = ()
#une_variable;;
- : bool ref = ref false
#une_constante := 5;;
Entrée interactive:
>une_constante := 5;;
>^^^^^^^^^^^^^
Cette expression est de type int,
mais est utilisée avec le type 'a ref.
#prefix := ;;
- : 'a ref -> 'a -> unit = <fun>



Importation


#sys__getenv;;
- : string -> string = <fun>
#getenv;;
Entrée interactive:
>getenv;;
>^^^^^^
L'identificateur getenv n'est pas défini.
Voir les noms exportés par sys
##open "sys";;
#getenv;;
- : string -> string = <fun>
#getenv "DISPLAY";;
- : string = ":0.0"
#getenv "PRINTER";;
Exception non rattrapée: Not_found
Cacher les noms exportés par sys
##close "sys";;
#getenv;; 
Entrée interactive:
>getenv;; 
>^^^^^^
L'identificateur getenv n'est pas défini.



Types produit cartésien


#9, 9.0, "9", `9`;;
- : int * float * string * char = 9, 9.0, 
"9", `9`
#let somme = function (x, y) -> x+y;;
somme : int * int -> int = <fun>
#let diagonale = function x -> (x, x);;
diagonale : 'a -> 'a * 'a = <fun>
#diagonale 2, diagonale 1.3 ;;
- : (int * int) * (float * float) = (2, 
2), (1.3, 1.3)
#let first = function (x, y) -> x;;
first : 'a * 'b -> 'a = <fun>
#first (1, 3);;
- : int = 1
#let (prem, sec) =  (1, 1.0);;
prem : int = 1
sec : float = 1.0



Types enregistrements


#type étudiant = {nom : string; âge : int};;
Le type étudiant est défini.
#let lambda = {nom = "LA"; âge = 20};;
lambda : étudiant = {nom = "LA"; âge = 
20}
#let anniv1 = function x -> 
   {nom = x.nom; âge = x.âge+1};;
anniv1 : étudiant -> étudiant = <fun>
#let anniv2 x = match x with
 | {nom = n; âge = a} -> 
   {nom = n; âge = a+1};;
anniv2 : étudiant -> étudiant = <fun>
#anniv1 lambda, lambda;;
- : étudiant * étudiant = {nom = "LA"; âge 
= 21}, {nom = "LA"; âge = 20}



Types sommes


#type couleur = 
 | Coeur | Pique | Carreau | Trèfle;;
Le type couleur est défini.
#type carte = 
 | Dame of couleur 
 | Petit of int*couleur 
 | Joker;;
Le type carte est défini.
#let valeurfoo c = match c with
 | Dame _ -> 20
 | Petit (10, c)-> 10
 | Petit (x, y) -> 
   if x = 9 & y = Coeur then 11 else 0
 | Joker -> 1;;
valeurfoo : carte -> int = <fun>
#let dameCoeur = Dame Coeur 
 and petit = Petit (7, Pique);;
dameCoeur : carte = Dame Coeur
petit : carte = Petit (7, Pique)
#valeurfoo petit;;
- : int = 0



Types récursifs


#type exp = 
 | V of string | C of int | P of exp*exp;;
Le type exp est défini.
#let rec eval e = match e with
 | V _ -> 0
 | C n -> n
 | P (e1, e2) -> (eval e1)+(eval e2);;
eval : exp -> int = <fun>
#let une_exp = P (P (V "x", C 25), C 10);;
une_exp : exp = P (P (V "x", C 25), C 10)
#eval une_exp;;
- : int = 35



Impératif


#for i = 0 to 9 do
   print_int i
 done;;
0123456789- : unit = ()
#let v=[|1;2;3|];;
v : int vect = [|1; 2; 3|]
#v.(2);;
- : int = 3
#for i = 0 to vect_length v-1 do
   print_int v.(i)
 done;;
123- : unit = ()
#let i = ref 0 in
 while !i < vect_length v do
    print_int v.(!i); incr i
 done;;
123- : unit = ()

Partie II
Présentation détaillée du langage




La programmation fonctionnelle



Expressions et valeurs

Fonctions

Fonctions récursives

Listes (début du filtrage)

Types produits

Types enregistrements

Types sommes

Types récursifs

Un peu d'ordre supérieur



La programmation impérative



Références
Création et type
#let compteur = ref (0);;
compteur : int ref = ref 0
Consultation du contenu courant (déréférencement)
#!compteur;;
- : int = 0
Modification du contenu (affectation, effet de bord)
#compteur:=2;;
- : unit = ()
#!compteur;;
- : int = 2
Exemple de fonction manipulant des références :
#let incrémente c = c := !c+1;;
incrémente : int ref -> unit = <fun>
#incrémente compteur; !compteur;;
- : int = 3
Attention, l'affectation d'une référence est différente de la redéfinition par un let d'une variable Caml :
#let x = 1;;
x : int = 1
#let f y = x+y;;
f : int -> int = <fun>
#let x = 2;;
x : int = 2
#f (0);;
- : int = 1
        
#let x = ref 1;;
x : int ref = ref 1
#let f y = !x+y;;
f : int -> int = <fun>
#x := 2;;
- : unit = ()
#f (0);;
- : int = 2

Tableaux


Tableaux à une dimension (vecteurs)


Figure 0.1 : Les principales notions sur les vecteurs

Création et type
#[|1; 2; 3|];;
- : int vect = [|1; 2; 3|]
#make_vect 4 2;;
- : int vect = [|2; 2; 2; 2|]
#let r = make_vect 3 "Bonjour";;
r : string vect = [|"Bonjour"; "Bonjour"; 
"Bonjour"|]
Consultation du contenu courant
#r;;
- : string vect = [|"Bonjour"; "Bonjour"; 
"Bonjour"|]
#r.(0);;
- : string = "Bonjour"
Modification du contenu
#r.(1) <- "tout"; r.(2) <- "le monde!";;
- : unit = ()
#r;;
- : string vect = [|"Bonjour"; "tout"; "le 
monde!"|]
Tableaux à deux dimensions (matrices)

Création, types et dimensions
#[|[|1; 2; 3|]; [|4; 5; 6|]; [|7; 8; 9|]|];;
- : int vect vect = [|[|1; 2; 3|]; [|4; 5; 
6|]; [|7; 8; 9|]|]
#make_matrix 2 1 "Bonjour";;
- : string vect vect = [|[|"Bonjour"|]; 
[|"Bonjour"|]|]
#let M = make_matrix 2 3 0;;
M : int vect vect = [|[|0; 0; 0|]; [|0; 0; 
0|]|]
#(* nombre de lignes *)
 vect_length M;; 
- : int = 2
#(* nombre de colonnes *)
 vect_length M.(0);; 
- : int = 3
Consultation du contenu courant
#M;;
- : int vect vect = [|[|0; 0; 0|]; [|0; 0; 
0|]|]
#M.(0).(2);;
- : int = 0
Modification du contenu
#M.(1).(0) <- 2; M.(1).(2) <- 5;;
- : unit = ()
#M;;
- : int vect vect = [|[|0; 0; 0|]; [|2; 0; 
5|]|]

Séquences
#print_string "Bonjour "; 
 print_string "tout le monde !";;
Bonjour tout le monde !- : unit = ()
#print_string;;
- : string -> unit = <fun>
#1+2;3;;
Entrée interactive:
>1+2;3;;
>^^^
Attention: cette expression est de type 
int,
mais est utilisée avec le type unit.
- : int = 3

Boucles

Exceptions



Programmation fonctionnelle vs impérative


Exemples dans les deux styles
#let rec fact = function n ->
   if n <= 0 then 1 else n*fact(n-1);;
fact : int -> int = <fun>
#let fact_imp = function n ->
   let temp = ref 1 in
     for i = 1 to n do
       temp :=!temp*i
     done;
   !temp ;;
fact_imp : int -> int = <fun>
#let rec fib1 = function n ->
   if n <= 1 then 1 
   else fib1(n-1)+fib1(n-2);;
fib1 : int -> int = <fun>
#let fib2 = function n ->
   let (cour, prec, temp) = 
       (ref 1, ref 1, ref 1) in
     for i = 1 to n-1 do
       temp := !cour;
       cour := !cour + !prec;
       prec := !temp
     done; !cour;;
fib2 : int -> int = <fun>
#let fib3 = function p ->
   let rec fib_accu prec cour n = 
     if p = n then cour
     else fib_accu cour (prec+cour) n+1 in
   if p <= 1 then 1 else fib_accu 1 1 1;;
fib3 : int -> int = <fun>

Partie III
Un exemple complet
complément sur les types polymorphes




Types


#type 'a arbre = Vide | Noeud of 'a * 'a arbre * 'a arbre;;
Le type arbre est défini.
ou bien
#type 'a arbre = Vide | Noeud of 'a arbre_non_vide
 and 'a arbre_non_vide = 
   { Étiquette: 'a; 
     Fils_gauche: 'a arbre; 
     Fils_droit: 'a arbre };;
Le type arbre est défini.
Le type arbre_non_vide est défini.
ou encore
#type ('a, 'b) arbre = 
 | Vide | Feuille of 'b | Noeud of ('a, 'b) arbre_non_vide
 and ('a, 'b) arbre_non_vide = 
   { Étiquette: 'a; 
     Fils_gauche: ('a, 'b) arbre; 
     Fils_droit: ('a, 'b) arbre };;
Le type arbre est défini.
Le type arbre_non_vide est défini.



Exemples




Figure 0.2 : mon_arbre

#let mon_arbre = Noeud 
   {Étiquette = 10;
    Fils_gauche = Noeud 
      {Étiquette = 5; 
       Fils_gauche = Feuille 2; Fils_droit = Feuille 8}; 
    Fils_droit = Noeud 
      {Étiquette = 30; 
       Fils_gauche = Vide; Fils_droit = Feuille 40}};;
mon_arbre : (int, int) arbre = Noeud ...
ou
#let mon_arbre = Noeud 
   {Étiquette = 10;
    Fils_gauche = Noeud 
      {Étiquette = 5; 
       Fils_gauche = Noeud 
         {Étiquette = 2; 
          Fils_gauche = Vide; Fils_droit = Vide};
       Fils_droit = Noeud 
         {Étiquette = 8; 
          Fils_gauche = Vide; Fils_droit = Vide}}; 
    Fils_droit = Noeud 
      {Étiquette = 30; 
       Fils_gauche = Vide; 
       Fils_droit = Noeud 
         {Étiquette = 40; 
          Fils_gauche = Vide; Fils_droit = Vide}}};;
mon_arbre : (int, 'a) arbre = Noeud ...


Figure 0.3 : mon_expr

#type op = 
 | Addition | Soustraction | Multiplication | Division;;
Le type op est défini.
#let mon_expr = Noeud
   {Étiquette = Addition; 
    Fils_gauche = Noeud
      {Étiquette = Multiplication; 
       Fils_gauche = Feuille 1; Fils_droit = Feuille 2};
    Fils_droit = Noeud
      {Étiquette = Soustraction; 
       Fils_gauche = Feuille 3;
       Fils_droit = Noeud 
         {Étiquette = Division; 
          Fils_gauche = Feuille 4; Fils_droit = Feuille 5}}};;
mon_expr : (op, int) arbre = Noeud ...



Imprimer l'arbre par un parcours infixe


#let rec print_arbre print_étiquette print_feuille arbre = 
 match arbre with
 | Vide -> ()
 | Feuille f -> print_feuille f
 | Noeud {Étiquette = e;Fils_gauche = fg;Fils_droit = fd} ->
     print_string "(";
     print_arbre print_étiquette print_feuille fg;
     print_étiquette e; 
     print_arbre print_étiquette print_feuille fd;
     print_string ")";;
print_arbre : ('a -> 'b) -> ('c -> unit) -> ('a, 'c) arbre 
-> unit = <fun>
#print_arbre print_int print_int mon_arbre;;
(((2)5(8))10(30(40)))- : unit = ()
#let print_op op = match op with
 | Addition -> print_string "+"
 | Soustraction -> print_string "-"
 | Multiplication -> print_string "*"
 | Division -> print_string "/";;
print_op : op -> unit = <fun>
#print_arbre print_op print_int mon_expr;;
((1*2)+(3-(4/5)))- : unit = ()



Trier une liste en utilisant un arbre binaire de recherche


#let rec insérer_arbre x arbre = match arbre with
 | Vide -> Feuille x
 | Feuille y -> 
     if x < y 
     then Noeud {Étiquette = y; Fils_gauche = Feuille x; 
                 Fils_droit = Vide} 
     else Noeud {Étiquette = y; Fils_gauche = Vide; 
                 Fils_droit = Feuille x}
 | Noeud {Étiquette = e;Fils_gauche = fg;Fils_droit = fd} ->  
     if x < e 
     then Noeud {Étiquette = e; 
                 Fils_gauche = insérer_arbre x fg; 
                 Fils_droit = fd}
     else Noeud {Étiquette = e; Fils_gauche = fg; 
                 Fils_droit = insérer_arbre x fd};;
insérer_arbre : 'a -> ('a, 'a) arbre -> ('a, 'a) arbre = 
<fun>
#let rec arbre_of_list l = match l with 
 | [] -> Vide
 | x::l' -> insérer_arbre x (arbre_of_list l');;
arbre_of_list : 'a list -> ('a, 'a) arbre = <fun>
#print_arbre print_int print_int 
   (arbre_of_list [ 2; 5; 4; 6; 3; 7; 1; 8; 0; 5 ]);;
((0(1(234)))5(((56)7)8))- : unit = ()
#let rec list_of_arbre arbre = match arbre with
 | Vide -> []
 | Feuille f -> [f]
 | Noeud {Étiquette = e;Fils_gauche = fg;Fils_droit = fd} ->
     (list_of_arbre fg)@[e]@(list_of_arbre fd);;
list_of_arbre : ('a, 'a) arbre -> 'a list = <fun>
#let tri l = list_of_arbre (arbre_of_list l);;
tri : 'a list -> 'a list = <fun>
#tri [ 2; 5; 4; 6; 3; 7; 1; 8; 0; 5 ];;
- : int list = [0; 1; 2; 3; 4; 5; 5; 6; 7; 8]
et maintenant en tenant compte d'une fonction d'ordre totale
#let rec insérer_arbre ordre x arbre = match arbre with
 | Vide -> Feuille x
 | Feuille y -> 
     if ordre x y 
     then Noeud {Étiquette = y; Fils_gauche = Feuille x; 
                 Fils_droit = Vide } 
     else Noeud {Étiquette = y; Fils_gauche = Vide; 
                 Fils_droit = Feuille x }
 | Noeud {Étiquette = e;Fils_gauche = fg;Fils_droit = fd} ->  
     if ordre x e 
     then Noeud {Étiquette = e; 
                 Fils_gauche = insérer_arbre ordre x fg; 
                 Fils_droit = fd}
     else Noeud {Étiquette = e; Fils_gauche = fg; 
                 Fils_droit = insérer_arbre ordre x fd};;
insérer_arbre :
 ('a -> 'a -> bool) -> 'a -> ('a, 'a) arbre -> ('a, 'a) 
arbre = <fun>
#let rec arbre_of_list ordre l = match l with 
 | [] -> Vide
 | x::l' -> insérer_arbre ordre x (arbre_of_list ordre l');;
arbre_of_list : ('a -> 'a -> bool) -> 'a list -> ('a, 'a) 
arbre = <fun>
#let rec list_of_arbre arbre = match arbre with
 | Vide -> []
 | Feuille f -> [f]
 | Noeud a ->
     (list_of_arbre a.Fils_gauche)@
     [a.Étiquette]@
     (list_of_arbre a.Fils_droit);;
list_of_arbre : ('a, 'a) arbre -> 'a list = <fun>
#let tri ordre l = list_of_arbre (arbre_of_list ordre l);;
tri : ('a -> 'a -> bool) -> 'a list -> 'a list = <fun>
#tri (prefix <) [ 2; 5; 4; 6; 3; 7; 1; 8; 0; 5 ];;
- : int list = [0; 1; 2; 3; 4; 5; 5; 6; 7; 8]
#tri (prefix >) [ 2; 5; 4; 6; 3; 7; 1; 8; 0; 5 ];;
- : int list = [8; 7; 6; 5; 5; 4; 3; 2; 1; 0]



Évaluation d'un arbre d'expression


#let rec évaluation arbre = match arbre with
 | Vide -> 0
 | Feuille i -> i
 | Noeud a ->
     let efg = évaluation a.Fils_gauche 
     and efd = évaluation a.Fils_droit in
     match a.Étiquette with 
     | Addition -> efg + efd
     | Soustraction -> efg - efd
     | Multiplication -> efg * efd
     | Division -> efg / efd;;
évaluation : (op, int) arbre -> int = <fun>
#évaluation mon_expr;;
- : int = 5



Expressions avec variables


#type constructeur = 
 | Variable | Constante | Plus | Multiplié;;
Le type constructeur est défini.
#let mon_exp = Noeud 
   {Étiquette = Plus; 
    Fils_gauche = Noeud 
      {Étiquette = Variable;
       Fils_gauche = Feuille 1; Fils_droit = Vide}; 
    Fils_droit = Noeud 
      {Étiquette = Plus; 
       Fils_gauche = Noeud 
         {Étiquette = Variable; Fils_gauche = Feuille 1;
          Fils_droit = Vide}; 
       Fils_droit = Noeud 
         {Étiquette = Constante; Fils_gauche = Feuille 3;
          Fils_droit = Vide}}};;
mon_exp : (constructeur, int) arbre = Noeud ...

Ce document a été traduit de LATEX par HEVEA.