Vous êtes sur la page 1sur 43

Assistant

abstraction concrète

Construire un programme sous le système interactif


Image d'écran du système interactif sous MSDOS

Une session Caml correspond à une boucle dans laquelle une lecture d'expressions est réalisée sur l'unité d'entrée
standard, chaque expression lue est soumise à une analyse lexicale puis à une analyse syntaxique, ensuite elle est
typée par le système d'inférence de types, avec affichage du type inféré, et pour terminer, évaluée avec affichage de
.la valeur obtenue en résultat
Exemple de session Caml Light
Au démarrage, le système interactif affiche la version de Caml Light active, suivie de l'invite "#" qui indique que le
système est en attente d'une entrée de l'opérateur
Caml Light version 0.71 >
#
à ce moment, si l'opérateur veut évaluer une expression telle que "12 + 35", il entre l'expression en la terminant
";;" par un double point-virgule
Caml Light version 0.71 >
;; 35 + #12
pour valider et transmettre l'expression au système interactif, il frappe la touche d'entrée dite retour chariot ou [CR].
A la suite de quoi, le système interactif effectue et affiche le typage et l'évaluation de l'expression. Ceci fait, le
.système affiche l'invite et se place, de nouveau, en attente
Caml Light version 0.71 >
[CR] ;; 35 + #12
int = 17 : -
#
Le cycle : nouvelle entrée -> typage-évaluation -> affichage -> nouvelle entrée, se poursuit jusqu'à ce que
.)(l'opérateur termine la session en entrant la commande quit
Caml Light version 0.71 >
[CR] ;; 35 + #12
int = 17 : -
......#
.......
[quit() ;; [CR#
.Au cours d'une session Caml, l'environnement global est modifié par les déclarations globales

Pour construire un programme sous le système interactif, il suffit de déclarer les types, exceptions, constantes,
.variables et fonctions qui seront aussitôt évaluées et introduites dans l'environnement de travail
On peut construire un fichier texte contenant la séquence des déclarations. Il suffit, alors, d'appeler ce fichier par la
.commande include pour retrouver l'environnement de travail ainsi défini
Il est aussi possible de charger le fichier source, avec la commande load, ou compilé, avec la commande
load_object. De cette façon il sera possible de retrouver l'environnemnt de travail au moyen de la directive #open
mais aussi de le libérer, au moyen de la directive #close

Charger un programme
La fonction include
La fonction load
La fonction load_object
La directive #open
: Trois commandes sont utilisées pour charger les fichiers de modules Caml
.(Les fonctions include et load pour charger les fichiers sources des modules (texte Caml•
.La fonction load pour charger les fichiers compilés des modules•
.La directive #open sert à ouvrir les modules chargés

Construire un programme exécutable indépendant


Programmation modulaire
Pour construire un programme exécutable indépendant, on écrit un fichier texte contenant la séquence des
.déclarations. Il suffit, ensuite, de compiler ce fichier avec le compilateur camlc
Exemple :
.On a produit un fichier texte nommé "progcaml.ml" qui contient le programme principal
Considérons que ce fichier utilise les fonctions des modules "module1.ml", avec son interface "module1.mli", et
.""module2.ml" associé à "module2.mli
.On compile les modules dans l'ordre de leur appel
camlc -c "module1.mli"
camlc -c "module1.ml"
camlc -c "module2.mli"
camlc -c "module2.ml"
Puis, on lance la production du code exécutable qui sera installé dans un fichier portant le nom choisi par le
.(programmeur ("progcaml.exe" dans l'exemple
camlc -o "progcaml.exe" "module1.zo" "module2.zo" "progcaml.ml"
dernière modification : 06/12/96
La lettre de Caml, numéro 7
Les sources des programmes Caml
; interface de la bibliothèque PATRICIA; implémentation de la bibliothèque PATRICIA
interface de la bibliothèque sur les séries formelles ; implémentation de la bibliothèque sur les séries formelles
.Retour à la page générale de La lettre de Caml

L'interface de la bibliothèque sur les arbres compactés de recherche :


type arbre_de_recherche =
{
chercher : string -> bool ;
insérer : string -> unit ;
supprimer : string -> unit
} ;;

value nouvel_arbre : unit -> arbre_de_recherche ;;


L'implémentation de la bibliothèque sur les arbres compactés de recherche :
let rec intervalle i j =
if i <= j then i :: (intervalle (i+1) j)
else [] ;;

let bits_of_char c =
let c' = int_of_char c
in
it_list (fun l i -> (c' lsr i) land 1 :: l)
[] (intervalle 0 7) ;;

let bits_of_string s =
list_it
(fun i l -> bits_of_char s.[i] @ l)
(intervalle 0 (string_length s - 1))
[0;0;0;0;0;0;0;0] ;;

type arbre = Feuille of string | Nud of int * arbre * arbre ;;

let rec skip k l =


if k = 0 then l
else skip (k - 1) (tl l) ;;

let recherche a s =
let rec aux l = function
| Feuille s' -> s = s'
| Nud(k,g,d)
-> try
let t :: q = skip k l
in
aux q (if t = 0 then g else d)
with _ -> false
in
aux (bits_of_string s) a ;;

let rec suppression a s =


let rec aux l = function
| Feuille s' when s <> s' -> Feuille s'
| Feuille _ -> failwith "Arbre vide !"
| Nud(k,Feuille s',d) when s' = s
-> ( match d with
| Feuille _ -> d
| Nud(k',g',d') -> Nud(k + k' + 1,g',d') )
| Nud(k,g,Feuille s') when s' = s
-> ( match g with
| Feuille _ -> g
| Nud(k',g',d') -> Nud(k + k' + 1,g',d') )
| Nud(k,g,d)
-> try
match skip k l with
t :: q -> if t = 0 then Nud(k,(aux q g),d)
else Nud(k,g,(aux q d))
with _ -> Nud(k,g,d)
in
aux (bits_of_string s) a ;;

let trouve_place s a =
let rec descend = function
| Feuille s' -> s'
| Nud(_,g,_) -> descend g
in
let rec aux l = function
| Feuille s' -> s'
| Nud(k,g,d)
-> try
match skip k l with
t :: q -> aux q (if t = 0 then g else d)
with _ -> descend g
in
aux (bits_of_string s) a ;;

let rec discrimine l1 l2 i =


match l1,l2 with
t1 :: q1,t2 :: q2
-> if t1 <> t2 then i,t1,t2
else discrimine q1 q2 (i + 1) ;;

let insertion a s =
let s' = trouve_place s a
in
if s = s' then a
else
let l,l' = (bits_of_string s),(bits_of_string s')
in
let i,c,_ = discrimine l l' 0
in
let rec aux j l = function
| Feuille s' as a
-> if c = 0 then Nud(j,Feuille s,a)
else Nud(j,a,Feuille s)
| Nud(k,g,d) as a
-> if j > k then
let t :: q = skip k l
in
if t = 0 then Nud(k,(aux (j - k - 1) q g),d)
else Nud(k,g,(aux (j - k - 1) q d))
else if j < k then
if c = 0 then Nud(j,Feuille s,Nud(k-j-1,g,d))
else Nud(j,Nud(k-j-1,g,d),Feuille s)
else (* j = k *)
failwith "Erreur irrécupérable"
in
aux i l a ;;

(*******************************************
ce type est défini dans le fichier .mli,
sa définition ne doit pas être répétée !

type arbre_de_recherche =
{ chercher : string -> bool ; insérer : string -> unit ; supprimer : string -> unit } ;;

*********************************************)

let nouvel_arbre () =
let a = ref (Feuille "")
in
{
chercher = (function s -> recherche !a s) ;
insérer = (function s -> a := insertion !a s) ;
supprimer = (function s -> a := suppression !a s)
} ;;
L'interface de la bibliothèque sur les séries formelles :
#open "num" ;;

type série_formelle ;;

value prefix +@ : série_formelle -> série_formelle -> série_formelle


and prefix -@ : série_formelle -> série_formelle -> série_formelle
and prefix *@ : série_formelle -> série_formelle -> série_formelle
and prefix /@ : série_formelle -> série_formelle -> série_formelle
and prefix @@ : série_formelle -> série_formelle -> série_formelle
and prefix ^@ : série_formelle -> num -> série_formelle
and prefix !@ : num list -> série_formelle
and prefix %@ : num -> série_formelle -> série_formelle

and
zéro : num
and un : num
and deux : num
and trois : num
and quatre : num
and cinq : num
and six : num
and sept : num
and huit : num
and neuf : num
and dix : num
and un_demi : num
and
moins_un : num
and moins_deux : num
and moins_trois : num
and moins_quatre : num
and moins_cinq : num
and moins_six : num
and moins_sept : num
and moins_huit : num
and moins_neuf : num
and moins_dix : num
and moins_un_demi : num
and
print_SF : série_formelle -> int -> unit
and print_par_défaut : série_formelle -> unit
and installe_impression : unit -> unit
and
crée_SF_de : (num -> num) -> série_formelle
and crée_SF_expo_de : (num -> num) -> série_formelle
and intégration_SF : série_formelle -> num -> série_formelle
and dérivation_SF : série_formelle -> série_formelle
and
sinus : série_formelle
and cosinus : série_formelle
and sinus_h : série_formelle
and cosinus_h : série_formelle
and tangente : série_formelle
and tangente_h : série_formelle
and arctangente : série_formelle
and arctangente_h : série_formelle
and exponentielle : série_formelle
and ln_un_plus_z : série_formelle
and arcsinus : série_formelle
and arcsinus_h : série_formelle
and catalan : série_formelle ;;
L'implémentation de la bibliothèque sur les séries formelles :
#open "num" ;;

type 'a glaçon =


| Gelé of unit -> 'a
| Connu of 'a ;;

type série_formelle = { Constante : num ; mutable Reste : série_formelle glaçon } ;;

let moins_un = num_of_int (-1) and moins_deux = num_of_int (-2) ;;


let [zéro;un;deux;trois;quatre;cinq;six;sept;huit;neuf;dix] = map num_of_int [0;1;2;3;4;5;6;7;8;9;10] ;;
let
[moins_un;moins_deux;moins_trois;moins_quatre;moins_cinq;moins_six;moins_sept;moins_huit;moins_neuf;moin
s_dix]
= map num_of_int [-1;-2;-3;-4;-5;-6;-7;-8;-9;-10] ;;
let un_demi = un // deux and moins_un_demi = moins_un // deux ;;

let reste_SF s = match s.Reste with


| Gelé r -> let a = r() in s.Reste <- Connu a ; a
| Connu a -> a ;;

let crée_SF_de f =
let rec crée n =
{ Constante = f n ;
Reste = Gelé (function () -> crée (n +/ un))
}
in
crée zéro ;;

let SF_de_poly l =
let rec crée = function
| [] -> { Constante = zéro ; Reste = Gelé (function () -> crée []) }
| a :: q -> { Constante = a ; Reste = Gelé (function () -> crée q) }
in
crée l ;;

let crée_SF_expo_de f =
let rec crée n nn =
{ Constante = (f n) // nn ;
Reste = Gelé (function () -> crée (n +/ un) (nn */ (n +/ un)))
}
in
crée zéro un ;;

let rec liste_des_coefficients s = function


| 0 -> []
| n -> s.Constante :: (liste_des_coefficients (reste_SF s) (n-1)) ;;

let rec zéro_SF () = { Constante = zéro ; Reste = Gelé zéro_SF } ;;

let rec zn_SF = function


| 0 -> { Constante = un ; Reste = Gelé zéro_SF }
| n -> { Constante = zéro ; Reste = Gelé (function () -> zn_SF (n-1)) } ;;

let rec addition_SF s t =


{ Constante = s.Constante +/ t.Constante ;
Reste = Gelé (function () -> addition_SF (reste_SF s) (reste_SF t)) } ;;

let rec soustraction_SF s t =


{ Constante = s.Constante -/ t.Constante ;
Reste = Gelé (function () -> soustraction_SF (reste_SF s) (reste_SF t)) } ;;

let rec multiplication_SF_num s n =


{ Constante = s.Constante */ n ;
Reste = Gelé (function () -> multiplication_SF_num (reste_SF s) n)
} ;;

let opposé_SF s = multiplication_SF_num s moins_un ;;

let rec intégration_SF s k0 =


{ Constante = k0 ;
Reste = Gelé (function() -> intègre_SF_depuis_un_certain_rang s un)
}
and intègre_SF_depuis_un_certain_rang s n =
{ Constante = s.Constante // n ;
Reste = Gelé (function () -> intègre_SF_depuis_un_certain_rang (reste_SF s) (n +/ un))
} ;;

let dérivation_SF s =
let rec dérivation_aux s n =
{ Constante = s.Constante */ n ;
Reste = Gelé (function () -> dérivation_aux (reste_SF s) (n +/ un))
}
in
dérivation_aux (reste_SF s) un ;;

let multiplication_SF s t =
let produit_de_Cauchy a b =
let b' = rev b
in
it_list2 (fun t x y -> t +/ x */ y) zéro a b'
in
let rec multiplie_aux s t sl tl =
let sl' = s.Constante :: sl
and tl' = t.Constante :: tl
in
{ Constante = produit_de_Cauchy sl' tl' ;
Reste = Gelé (function () -> multiplie_aux (reste_SF s) (reste_SF t) sl' tl')
}
in
multiplie_aux s t [] [] ;;

let composition_SF s t =
let rec intervalle i j =
if i > j then []
else i :: (intervalle (i + 1) j)
in
let rec k_somme k s = (* k_somme 3 6 renvoie [[4; 1; 1]; [3; 2; 1]; [3; 1; 2]; ... *)
if s = 0 then []
else if k = 1 then [ [ s ] ]
else it_list
(fun ll i -> (map (function l -> i :: l) (k_somme (k - 1) (s - i))) @ ll)
[] (intervalle 1 s)
in
let coeff av bv =
let n = vect_length av - 1
in
let sbk l = it_list (fun x i -> x */ bv.(n - i)) un l
in
it_list
(fun s k -> s +/ av.(n-k) */ (it_list
(fun x l -> x +/ (sbk l))
zéro
(k_somme k n)))
zéro
(intervalle 1 n)
in
let rec aux al bl s t =
let al' = s.Constante :: al
and bl' = t.Constante :: bl
in
{ Constante = coeff (vect_of_list al') (vect_of_list bl') ;
Reste = Gelé(function () -> aux al' bl' (reste_SF s) (reste_SF t))
}
in
if t.Constante <>/ zéro then failwith "La composée a(b(z)) n'existe que si v(b) > 1" ;
{ Constante = s.Constante ;
Reste = Gelé(function () -> aux [ s.Constante ] [ t.Constante ]
(reste_SF s) (reste_SF t))
} ;;

let un_plus_z_puissance_a_SF a =
let rec aux coef k =
let k' = k +/ un
in
{ Constante = coef ;
Reste = Gelé (function () -> aux (coef */ (a -/ k) // k') k')
}
in
{ Constante = un ;
Reste = Gelé (function () -> aux a un)
} ;;

let un_sur_a_plus_z_SF a =
if a =/ zéro then failwith "1/z n'a pas de développement en série formelle" ;
let a' = zéro -/ a
in
let rec aux coeff =
{ Constante = coeff ;
Reste = Gelé (function () -> aux (coeff // a'))
}
in
aux (un // a) ;;

let rec division_SF s t =


let rec Cauchy_inverse a b t0 sn =
let b' = tl (rev b)
in
(sn -/ (it_list2 (fun s x y -> s +/ x */ y) zéro a b')) // t0
in
let rec divise_aux s t ul tl t0 =
let tl' = t.Constante :: tl
in
let u_n = Cauchy_inverse ul tl' t0 s.Constante
in
{
Constante = u_n ;
Reste = Gelé (function ()
-> divise_aux
(reste_SF s) (reste_SF t)
(u_n :: ul) tl' t0)
}
in
if t.Constante =/ zéro then
if s.Constante =/ zéro then division_SF (reste_SF s) (reste_SF t)
else failwith "Division impossible : valuation du numérateur inférieure à celle du dénominateur"
else
divise_aux s t [] [] t.Constante ;;

let puissance_SF_num s n =
let a = s.Constante
in
try
multiplication_SF_num
(composition_SF
(un_plus_z_puissance_a_SF n)
{
Constante = zéro ;
Reste = Gelé(function () -> reste_SF (multiplication_SF_num s (un // a)))
})
(if a =/ un then un else a **/ n)
with _ -> failwith "Exponentiation impossible" ;;

let rec évalue_SF s x n =


if n = 0 then s.Constante
else s.Constante +/ x */ (évalue_SF (reste_SF s) x (n-1)) ;;
let prefix +@ = addition_SF
and prefix -@ = soustraction_SF
and prefix *@ = multiplication_SF
and prefix /@ = division_SF
and prefix @@ = composition_SF
and prefix ^@ = puissance_SF_num
and prefix !@ = SF_de_poly
and prefix %@ n s = multiplication_SF_num s n ;;

#open "format" ;;

let print_num n = print_string (string_of_num n) ;;

let print_variable = function


| 0 -> false
| 1 -> print_string " z" ; true
| n -> print_string " z^" ; print_int n ; true ;;

let print_term plus degré s =


let c = s.Constante in
if c =/ zéro then false else
if c =/ un then begin print_string plus ; print_variable degré end else
if c =/ moins_un
then begin print_string "- " ; print_variable degré end
else
begin
if c >=/ zéro then print_string plus else print_string "- " ;
print_num (abs_num c) ;
print_variable degré
end ;;

let rec print_SF s until =


open_hovbox 1;
let c = s.Constante
in
if until == 0 then print_num c else
let rest = ref s
in
let nul = ref true
in
if not (c =/ zéro) then (print_num c ; print_space() ; nul := false) ;
for i = 1 to until do
rest := reste_SF !rest;
let delim = if !nul then "" else "+ "
in
if print_term delim i !rest then ( nul := false ; print_space())
done ;
if not !nul then print_string "+ " ;
print_string "O(z^"; print_int (succ until) ;
print_string ")" ;
close_box() ;;

let print_par_défaut s = print_SF s 11 ;;

let installe_impression () = install_printer "print_par_défaut" ;;

let rec sinus = { Constante = zéro ;


Reste = Gelé (function () -> intègre_SF_depuis_un_certain_rang cosinus un) }
and cosinus = { Constante = un ;
Reste = Gelé (function () -> intègre_SF_depuis_un_certain_rang (opposé_SF sinus) un) } ;;
let rec sinus_h = { Constante = zéro ;
Reste = Gelé (function () -> intègre_SF_depuis_un_certain_rang cosinus_h un) }
and cosinus_h = { Constante = un ;
Reste = Gelé (function () -> intègre_SF_depuis_un_certain_rang sinus_h un) } ;;

let tangente = sinus /@ cosinus ;;


let tangente_h = sinus_h /@ cosinus_h ;;
let arctangente = intégration_SF ((!@ [un]) /@ (!@ [un;zéro;deux])) zéro ;;
let arctangente_h = intégration_SF ((!@ [un]) /@ (!@ [un;zéro;moins_deux])) zéro ;;
let exponentielle = crée_SF_expo_de (function _ -> un) ;;
let ln_un_plus_z = intégration_SF (un_plus_z_puissance_a_SF moins_un) zéro ;;
let arcsinus = intégration_SF ((!@ [un;zéro;moins_deux]) ^@ moins_un_demi) zéro ;;
let arcsinus_h = intégration_SF ((!@ [un;zéro;deux]) ^@ moins_un_demi) zéro ;;

let catalan = ((!@ [un]) -@ ((!@ [un;moins_quatre]) ^@ un_demi))


/@ (!@ [zéro;deux]) ;;

.Retour à la page générale de La lettre de Caml

Références
abstraction concrète

Bibliographie
Internet

Bibliographie
.Concepts et outils de la programmation .[1]
.Accart Hardin T., Donzeau-Gouge Vigié V
.Paris, InterEditions .(1993)
.ISBN 2-7296-0419-7
.Introduction à la logique contemporaine .[2]
.Blanché Robert
.Paris, Armand Colin .(1968)
.ISBN 2-200-32008-6
.The art and science of logic .[3]
.Bonevac Daniel
.Moutain View, Mayfield .(1990)
.ISBN 0-87484-805-9
.The Caml Light system release 0.5. Documentation and user's manual .[4]
.Leroy X., Mauny M
.Rocquencourt, INRIA .(1992)
.ISBN 2-7261-0748-6
.Manuel de référence du langage Caml .[5]
.Leroy Xavier, Weis Pierre
.Paris, InterEditions .(1993)
.ISBN 2-7296-0492-8
.The implementation of functionnal languages .[6]
.Peyton Jones S. L
.Englewood Ciffs, Prentice-Hall .(1987)
.ISBN 0-13-453333-9 PBK
.Functionnal programming and parallel graph rewriting .[7]
.Plasmeijer R., van Eekelen M
.Wokingham, Addison-Wesley .(1993)
.ISBN 0-201-41663-8
.Méthodes de logique .[8]
.Quine Willard V.O
.Paris, Armand Colin .(1972)
.ISBN 2-200-31081-1
.Elements of functionnal programming .[9]
.Reade Chris
.Wokingham, Addison-Wesley .(1989)
.ISBN 0-201-12915-9
.Lire Lisp .[10]
.Roy J.P., Kiremitdjian G
.(1985)
.Paris, Cedic
.ISBN 2-7124-0573-0
.Le langage Caml .[11]
.Weis Pierre, Leroy Xavier
.Paris, InterEditions .(1993)
.ISBN 2-7296-0493-6
.Approche fonctionnelle de la programmation .[12]
.Guy Cousineau, Michel Mauny
.Paris, Ediscience international .(1995)
.ISBN 2-84074-114-8
.Option informatique : cours pour la Sup MPSI .[13]
.Denis Monasse
.Paris, Librairie Vuibert .(1996)
.ISBN 2-7117-8831-8

Internet
.INRIA .[1]
http://pauillac.inria.fr/caml/index-fra.html
/ftp://ftp.inria.fr/lang/caml-light

dernière modification : 06/12/96

Mémento
abstraction concrète

Syntaxe Caml
.Les définitons syntaxiques décrivent les mecanismes de construction des expressions du langage Caml

: La syntaxe des phrases du langage Caml est présentée en notation B.N.F. (Backus-Naur Form), sous la forme
identificateur_de_phrase ::= forme_syntaxique
: Dans la suite, la syntaxe d'une phrase Caml quelconque est décrite par une règle de réécriture selon le modèle
partie gauche de la règle ::= partie droite.
.Le symbole «::=» est appelé symbole de réécriture

La syntaxe de la phrase désignée par un identificateur de phrase en italique dans la partie gauche est décrite par la
.partie droite de la forme B.N.F

: La partie droite de la règle de réécriture exprime la syntaxe de la phrase par une suite de symboles qui sont
soit des identificateurs de phrase (en italique), Dans ce cas ils figurent aussi comme partie gauche•
.(d'une autre description B.N.F., et parfois de la même description (définition récursive
.(soit des symboles ou des mots-clés du langage Caml (en caractères gras non italique•
Pour éviter les confusions et les ambiguités avec les symboles utilisés dans le langage Caml, les symboles B.N.F.,
autres que le symbole de réécriture, ne sont pas employés. Par conséquent, les formes syntaxiques alternatives ou
.optionnelles, et les répétitions d'occurrences, seront définies de manière explicite, et parfois informelle
Exemple de syntaxe
expression_fonctionnelle ::= function filtrage
Dans cet exemple «expression_fonctionnelle» est l'identificateur de la forme de phrase expliquée par la
.description B.N.F., «function» est un mot-clé de Caml et «filtrage» est un identificateur de phrase

Typage Caml
.Règles de typage appliquées par le synthétiseur de types Caml

: Le typage des expressions du langage Caml est présenté en langage Caml, sous la forme
expression caml : expression de type caml
L'expression Caml «expression caml» de la partie à gauche du symbole de typage : est typée par une expression de
.type «expression de type caml» dans la partie droite

Une expression de type en Caml est formée à partir d'identificateurs de types Caml et d'expressions de types Caml
.combinés par des opérateurs sur les types
Exemples de typage
"bonjour" : string
`z` : char
function x -> x + 8 : int -> int
Dans ces exemples "bonjour", `z`, et (function x -> x+8) sont des expressions Caml, string, char et
.(int -> int), sont des expressions de type en langage Caml
Règles de typage
: Les règles de trypage sont données sous la forme

Hypothèses

----------

Conclusion

Exemple de règle de typage


Dans notre exemple, E1:bool, E2:T et E3:T sont les hypothèses. Tandis que )if E1 then E2 else
.E3(:T est la conclusion de la règle

E1:bool E2:T E3:T

-------------------------

)if E1 then E2 else E3(:T

Evaluation Caml
.Principes d'évaluation des expressions Caml

: L'évaluation des expressions du langage Caml est présentée sous la forme


Evaluation)expression_caml( => valeur_caml
est évaluée à la valeur qu'elle ‫ ق‬L'expression Caml (expression_caml) de la partie à gauche du symbole d'évaluation
.exprime (valeur_caml) dans la partie droite
Exemple d'évaluation
# let a = 40 ;;
a : int = 40

Evaluation)a(
=> Evaluation)40(
=> 40
Evaluation)a + 5(
=> Evaluation)Evaluation)a( + Evaluation)5((
=> Evaluation)Evaluation)40( + 5(
=> Evaluation)40 + 5(
=> Evaluation)45(
=> 45

Notation et symboles
Symboles utilisés pour décrire le modèle de la machine Caml

Grammaire Caml
.Les définitions syntaxiques du langage Caml rassemblées

dernière modification : 06/12/96

Syntaxe Caml
abstraction concrète

Définition simple.1
Définition multiple.2
Définition locale simple.3
(Définition locale simple (variante.4
Définitions locales emboîtées et multiples.5
(Définitions locales emboîtées et multiples (variante.6
Expression conditionnelle.7
Type construit simple.8
Type construit composé.9

Type produit.10
Type enregistrement.11
Fonctions à une variable.12
(Fonctions à n variables (1 argument.13
(Fonctions à n variables (n arguments.14
Fonction : Syntaxe 1ère forme.15
Fonction : Syntaxe 2ème forme.16
Fonction : Syntaxe 3ème forme.17
Fonction : Syntaxe 4ème forme.18
Applications.19
Définition récursive simple.20
Définition récursive multiple.21
Définition récursive locale.22
(Définition récursive locale (variante.23
Filtrage par composants.24
Filtrage par valeurs.25
Filtrage par cas.26
Gardes.27
Conditionnelle par cas.28
Fonction définie par filtrage.29
Types synonymes.30
Type somme.31
Listes.32
Définition d'une exception.33
Déclenchement d'exception.34
Gestion d'exception.35
Module de définition.36
Directive.37
Type abstrait.38
Module d'interface.39
Types polymorphes.40
Contraintes de types.41
Syntaxe de flux.42
Syntaxe du filtrage de flux.43
dernière modification : 06/12/96 .44

Manuel : Notions de base


abstraction concrète

Commentaires
".Sans commentaire "
Bien qu’inutiles pour l’exécutant machine, et ignorés par le compilateur, les commentaires sont judicieusement
utilisés par le programmeur, pour documenter les programmes. Dans le langage Caml, ils sont encadrés par les
symboles "(*" au début et "*)" à la fin du commentaire et peuvent être placés à n'importe quelle position dans la
ligne de programme. Tous les caractères se trouvant entre "(*" et "*)" sont ignorés par le compilateur. Enfin Caml
.accepte les commentaires emboîtés

Exemple de commentaire simple


(* ceci est un commentaire en Caml *)
Exemple de commentaire emboîté

(* début de l'exemple 2
ceci est un autre commentaire en Caml
avec mise en page
et sur plusieurs lignes
(* ceci est un commentaire emboîté dans l'exemple 2 *)
(* ceci est un autre commentaire
(* emboîté à
(* plusieurs
(* niveaux d'imbrication *) *) *) *)
fin de l'exemple 2 *)

Identificateurs et expressions
Et s'il me dit un nom "
C'est celui d'un coteau
C'est celui d'une fille
Et celui d'un bateau
C'est celui d'une ville
".Et celui d'un château
.Gilles Vigneault

Identificateurs
Les identificateurs sont utilisés en Caml pour nommer des entités telles que des variables, des fonctions, des types,
des éléments de structures de ces objets comme les étiquettes (noms de champs), les constructeurs (de types ou de
valeurs). Le langage Caml distingue les majuscules des minuscules. Le premier caractère d’un identificateur est
obligatoirement une lettre. Sa longueur, le nombre des caractères qui le composent, doit être comprise dans un
intervalle de 1 à 256 caractères. Les caractères suivants peuvent être des lettres, des chiffres, des apostrophes et des
tirets, à condition que deux tirets consécutifs soient séparés par au moins un autre caractère.
Exception à la règle, deux tirets sont immédiatement consécutifs (ou adjacents) quand l’identificateur désigne le
nom d’une fonction d’un module de bibliothèque. Dans ce cas les deux tirets adjacents servent à séparer les deux
parties du nom, en premier, celui du module, et en second, celui de la fonction.
Par exemple : sort__merge désigne la fonction merge du module sort.

Les identificateurs doivent être différents des mots-clés du langage Caml tels que :
function, if, then, else, true, false, etc.
Exemples d'identificateurs valides et distincts
un, deux, A, X', X'', ALPHA, Alpha1, alpha_1, B5, autre_exemple, autre_exemple_2,
carre_d'as, FUNCTION, Then
HECTOR, Hector, hector, HecTor, heCtOr, hectoR
i_den't_if'ic_ateur12'''
Exercice 1
.Rechercher pourquoi les identificateurs suivants ne sont pas valides
.un, _deux, 'trois, 8A, carre d'as, function, then_1

Solution

Manuel : Identificateurs

Expressions
: Une expression Caml est
soit une expression atomique ou expression élémentaire non décomposable en expressions plus simples.•
Par exemple tous les identificateurs, ainsi que les constantes numériques (entières ou décimales), les
chaînes de caractères, ou encore les valeurs caractères, telles que 9, 1.047, `H`, "Jean", sont des expressions
.atomiques
soit une expression composée ou expression formée par une combinaison d'expressions plus simples•
.atomiques ou composées, et d'opérateurs
Type et valeur d'une expression
Le concept de type est à rapprocher de la notion mathématique d'ensemble. Le type d'une expression représente
.l'implémentation de l'ensemble auquel appartient la valeur obtenue par l'évaluation de cette expression

Quelques types pré-définis


Le type int
Le type int implémente un sous-ensemble fini des nombres entiers dans l'intervalle [-230,230-
1].
Les principales opérations pré-définies sur les entiers sont :
. l'addition +,

. la soustraction -,

. la multiplication *,

. la division entière /,

. le reste de la division entière mod


. et les comparaisons ( >, >, >=, >= ).

Le type float
Le type float implémente un sous-ensemble fini des nombres décimaux.
Les principales opérations pré-définies sur les décimaux sont :
. l'addition +.,

. la soustraction -.,

. la multiplication *.,

. la division /.

. et les comparaisons ( >., >., >=., >=. ).

Le type bool
Le type bool implémente l'ensemble des valeurs booléennes : true et false. Les opérations
pré-définies sur les booléens sont : la négation not, la disjonction || (ou or) et la
conjonction && (ou &).

Le type char
Le type char implémente un ensemble des caractères codés par les entiers 0 à 255, les
codes 0 à 127 correspondent aux caractères ASCII. Les valeurs de ce type sont notées au
moyen du caractère qu'elles représentent, placé entre quotes, ou au moyen du numéro de
code à trois chiffres ASCII précédé du backslash \ et placé entre quotes, ou encore au
moyen d'un symbole spécial (n = nouvelle ligne, t = tabulation) précédé du backslash \ et
placé entre quotes, par exemple : `a`, `A`, `$`, `9`, `\065`, `\n`.
Le type string
Le type string implémente un sous-ensemble des chaînes de caractères de longueur [0,2
16
-1]. Les chaînes de caractères sont notées entre guillemets, par exemple : "exemple de
chaîne". L'opérateur de concaténation de chaînes de caractères est noté ^.
Par exemple : la concaténation des deux chaînes "bon" et "jour" : "bon" ^ "jour" donnera
la chaîne "bonjour".
Le type unit
Le type unit ne possède qu'une valeur, la valeur )( qui signifie «rien».

Le type unit est utilisé :

• pour les fonctions qui ne reçoivent pas d'argument (unit -> T),

• ou qui ne retournent aucun résultat (T -> unit).

L'égalité structurelle et l'inégalité structurelle


L'égalité structurelle = et l'inégalité structurelle >> sont pré-définies pour tous les types sauf les valeurs
.fonctionnelles

Déclaration de types et synthèse de types


Caml est un langage fortement typé, ce qui rend possible un contrôle rigoureux du typage des expressions
permettant de déceler certaines erreurs de programmation. Pour ce faire, l'exécutant doit connaître (déclaration de
types) ou reconnaître (synthèse de types) le type des objets qui lui sont proposés. La déclaration de types est la
technique mise en œuvre dans le cas de certains langages tels que Pascal, C, Ada. Dans ce cas chaque objet figurant
.dans le programme est préalablement déclaré avec la mention explicite du type auquel il appartient

Au contraire, la synthèse des types dispense de toute déclaration préalable du type de l'objet. En effet, dans ce
.second cas, le type de l'objet est déduit du contexte par l'application de règles d'inférence de types

expressions de type et paramètres de types


Les expressions de type comprennent les expressions simples et les expressions composées de type. Les expressions
simples de type sont formées par la mention d'un identificateur de type tel que float, int, char, etc. Une
expression composée de type est une expression dans laquelle figurent des expressions de type combinées entre elles
.>- par des opérateurs sur les types tels que * et

Les expressions de type peuvent comporter des paramètres de types. Ceux-ci peuvent être remplacés par un type ou
une expression de type quelconques (opération de spécialisation). Les paramètres de types sont représentés par un
.identificateur précédé d’une apostrophe ('identificateur), par exemple 'a et 'b
Exemples d'expressions de type :
)* expressions simples de type *(
int
bool
)* expressions composées de type *(
int * int
int -> int
)char * int( -> bool
)* expressions paramétrées de type *(
'a -> 'a )* int -> int est une spécialisation de 'a -> 'a *(
'a -> int -> 'b
Constructeurs de types
.Les identificateurs qui servent à nommer les types tels que int, float, char, sont des constructeurs de types

Définitions et environnement
définitions et liaisons
Une définition construit une liaison entre un nom, la valeur à laquelle il est associé et son type. La collection des
liaisons ainsi créées est appelée environnement. Les définitions successives ont donc pour effet de modifier
.l'environnement
Dans ce qui suit, nous simplifierons en considérant la liaison comme une paire qui sera selon le contexte de l'étude :
.soit une paire (nom, valeur) dans un contexte d'évaluation, soit une paire (nom, type) dans un contexte de typage

Environnements
Dans un contexte d'évaluation, considérant un ensemble fini N d'identificateurs n et un ensemble fini V de valeurs v,
une définition mathématique de la notion d'environnement peut être donnée par : le graphe d'une bijection de N sur
.V
Ou encore, ce qui est équivalent, par : l'ensemble des paires (n, v), telles que si cet environnement contient deux
.'paires (n, v) et (n, v') alors v = v

Une autre approche représente un environnement par une liste de paires (n, v) dans laquelle la dernière liaison créée
est placée en tête de liste, et lors de la recherche d'un identificateur dans la liste, à partir de la tête, seule la première
.occurrence d'une liaison associée à cet identificateur est retenue

Le même raisonnement, dans un contexte de typage, mènera à des définitions semblables en substituant un ensemble
.fini T de types t à V

: La liste des liaisons (ni, vi) formant l'environnement Eactuel sera notée
Eactuel = (nn, vn) ... (n2, v2) (n1, v1) liaisons_Einitial
ou bien
Eactuel = (nn, vn) ... (n2, v2) (n1, v1) liaisons_Einitial
ou bien encore
Eactuel = (nn, vn) ... (n2, v2) (n1, v1) Einitial
(si j > i alors la création de la liaison (nj, vj) est plus récente que celle de (ni, vi

Définitions globales
Syntaxe : définition globale simple

définition ::= let identificateur = expression

Syntaxe : définition globale multiple

définition ::=

let identificateur_1 = expression_1


and identificateur_2 = expression_2

...

and identificateur_n = expression_n

Exemples de définitions globales


#let nombre_1 = 102 ;;
nombre_1 : int = 102
#let nombre_2 = 57 ;;
nombre_2 : int = 57
#let un_nom = "PAUL LEGENDRE" ;;
un_nom : string = "PAUL LEGENDRE"
#let autre_nom = "JULES CESAR" ;;
autre_nom : string = "JULES CESAR"
#let caractère = `W` ;;
caractère : char = `W`
#let calcul = 473 + nombre_1
and alpha = nombre_1 * nombre_2
and x = "ceci est une chaine de caracteres"
and x' = `A` ;;
calcul : int = 575
alpha : int = 5814
x : string = "ceci est une chaine de caracteres"
x' : char = `A`

définitions locales
Les définitions locales construisent des environnements temporaires durant l'évaluation de l'expression dans laquelle
elles sont incluses. Au terme de l'évaluation de l'expression contenant des définitions locales, l'environnement global
.n'est pas modifié
Syntaxe : définition locale simple

définition_locale ::= let identificateur = expression_A

in expression_B

Exemple
#let a = -7 and b = -4 in 5*a*b + 3*)a - b( - a*a - b*b ;;
- : int = 66
Syntaxe : définition locale simple (variante)
Dans ses extensions de langage, Caml-Light procure une variante à la syntaxe précédente. Toutefois, ces extensions
.sont propres à Caml-Light, et seront éventuellement modifiées ou supprimées dans les versions futures du langage

définition_locale ::= expression_B

where identificateur = expression_A

Exemple
#5*a*b + 3*)a - b( - a*a - b*b
where a = -7 and b = -4 ;;
- : int = 66
Syntaxe : définitions locales emboîtées et multiples

définitions_emboitées_multiples ::=

let ident_1 = expr_1 and...and ident_i = expr_i in

let ident_)i+1( = expr_)i+1(

and...and ident_j = expr_j in

let ident_k = expr_k and...and ident_n = expr_n in expression

Syntaxe : définitions locales emboîtées et multiples (variante)

définitions_emboitées_multiples ::=

expression

where ident_1 = expr_1 and...and ident_i = expr_i

where ident_)i+1( = expr_)i+1(

and...and ident_j = expr_j

where ident_k = expr_k and...and ident_n = expr_n

Remarque : Il est important de noter que les quatre formes syntaxiques


précédentes ne sont pas des définitions globales. Il s'agit d'expressions
.contenant des définitions locales

A un niveau donné d’imbrication, les définitions sont parallèles, comme le


: montre l’exemple suivant
# let a = 1 in
let a = 2 and b = a in
a + b ;;
- : int = 3 )* et non pas 4 *(

Exemple de définitions emboîtées


#let b = 27 in b + b * b - 25 ;;
- : int = 731
#let titre = "Software tools in Pascal"
and auteur = "Brian W. Kernighan, P.J. Plauger" and deux_points = " : "
in titre ^ deux_points ^ auteur ;;
- : string = "Software tools in Pascal : Brian W. Kernighan, P.J. Plauger"
#let h = 8 and i2 = -1 in let t = 3 * h + 7 * i2 in t * t ;; (* syntaxe avec "in" *)
- : int = 289
#t * t where t = 3 * h + 7 * i2 where h = 8 and i2 = -1 ;; (* syntaxe avec "where" *)
- : int = 289
#let delta = let a = 5 and b = 8 and c =-43 in b*b-4*a*c ;;
delta : int = 924
Typage d'une définition locale
Chaque identificateur est du type de la valeur résultant de l'évaluation de l'expression à laquelle il est associé dans la
définition. Si E’ est une expression du type T’ et si T est le type de l'expression évaluée avec un environnement
temporaire dans lequel l’identificateur X est lié à la valeur de E’. Cette règle peut être exprimée par la notation
suivante :
Règle de typage d'une définition locale simple

E':T' ,)X,T'(E:T

)let X = E'in E)X((:T

Evaluation de définition et modification de l'environnement


Expressions
Environnement global et environnements temporaires
Typage et évaluation
(* debut de session *) Einitial = E
;; let a = 8#
a : int = 8

E1 = )a,8(E
let a = 5#
;; in 2 * a
int = 10 : -

E3_temp = )a,5(E2...............
E3 = E2
Exercice 2
Soit une session Caml dans un environnement Ei, on effectue les définitions
: suivantes
1. # let a = 30;;
2. # let b = a + 20;;
3. # let a = b + 5;;
4. # a;;
5. # b;;
6. # let c = 8 in c * c + a + b;;
7. # let a = 2 in a * a + a * b + b;;
Décrire l'environnement à chaque définition. Quelles sont les valeurs
? associées aux identificateurs a, b et c, après la dernière définition

Solution

Manuel : Type et valeur des expressions


Manuel : Définitions et environnement
Exercice 3
: Depuis l'environnement Eo, on entre la phrase Caml suivante
#let taux = 2 in
let alpha = 5 in
let coef = taux * alpha + alpha in
taux * alpha + coef * alpha ;;
? Décrire le nouvel environnement. Quel est le résultat affiché

Solution

Manuel : Type et valeur des expressions


Manuel : Définitions et environnement
Exercice 4
Au cours d'une session Caml, dans un environnement Env, on effectue les deux
: définitions suivantes
1. # let a =
let a = 3 and b = 2 in
let a = a + b and b = a - b in a * a - b * b ;;
2. # let b = 2 in a * a + a * b + b;;
? Qu'affiche le système interactif après chaque évaluation

Solution

Manuel : Type et valeur des expressions


Manuel : Définitions et environnement
Les modules
La décomposition fonctionnelle est une incitation positive à la construction de programmes structurés et modulaires.
Dans cette optique, le langage Caml offre la possibilité de découper les gros programmes en plusieurs modules
.distincts qui sont ensuite compilés séparément

L'expression conditionnelle
L’expression conditionnelle délivre un résultat dépendant d’une condition exprimée par une expression booléenne.
Le typage fort de Caml exige que la valeur de l’expression conditionnelle, quand la condition est vraie, et la valeur
.de l’expression conditionnelle, quand la condition est fausse, soient du même type

: La syntaxe de l’expression conditionnelle met en œuvre trois expressions


,une condition, expression booléenne•
une expression à évaluer si la condition est vraie : expression_alors de type quelconque T et•
.une expression à évaluer si la condition est fausse : expression_sinon de type T•

Syntaxe, typage, évaluation de l'expression conditionnelle


Syntaxe de l'expression conditionnelle

expression_conditionnelle ::=

if expression_booléenne

then expression_alors

else expression_sinon

Règle de typage d'une expression conditionnelle

E1:bool E2:T E3:T


)if E1 then E2 else E3(:T

Evaluation d'une expression conditionnelle


Lors de l'évaluation de l'alternative if E1 then E2 else E3 dans l'environnement courant Env, E1 est une
expression booléenne exprimant une condition de type bool dont l'évaluation donne une valeur booléenne. Les
expressions E2 et E3 sont du même type T. Si E1 vaut true l'évaluation de E2 donne E2 : T=a, sinon
l'évaluation de E3 donne E3 : T = b. Quel que soit le résultat de l’évaluation de la condition E1, une seule
.branche de l’expression conditionnelle est évaluée, soit E2, soit E3
1. Evaluation(if E1 then E2 else E3)
2. Evaluation(if Evaluation(E1) then E2 else E3)
- cas ou la condition est vraie, E1 : bool = true
3. Evaluation(if true then Evaluation(E2) else E3)
4. Evaluation(E2) = a
- cas ou la condition est fausse, E1 : bool = false
3. Evaluation(if false then E2 else Evaluation(E3))
4. Evaluation(E3) = b
Règle d'évaluation d'une expression conditionnelle

Evaluation)if E1 then E2 else E3(

-----------------------------------------------------------------

[)E1=true( --> Evaluation)E2(] OU [)E1=false( --> Evaluation)E3(]

Exemples d'expressions conditionnelles


#let x = 0.0 in
if x = 0.0 then 1.0 else sin(x) /. x ;;
- : float = 1.0
#let feu = "VERT" in
if feu = "ROUGE" then "STOP"
else if feu = "ORANGE" then "RALENTIR"
else if feu = "VERT" then "PASSER"
else "Erreur feu : "^feu ;;
- : string = "PASSER"
Contrôle de l'évaluation de l'expression conditionnelle
Dans une expression, l'utilisation de failwith message déclenche une exception Failure message qui
.provoque l'arrêt de l'évaluation de l'expression

De la même façon, l'utilisation de invalid_arg message déclenche une exception Invalid_argument


.message qui provoque l'arrêt de l'évaluation de l'expression
Contrôle au moyen de la fonction failwith

controle_d'évaluation ::=

failwith expression_chaine_message

Dans certaines circonstances l'évaluation d'une expression ne peut terminer,


conduisant ainsi à des situations non contrôlées par l'utilisateur. Ici, par
exemple, la division par zéro déclenche l'exception pré-définie du système
.Caml : Division_by_zero
#let a = 55 and x = 0
in a / x ;;
Uncaught exception: Division_by_zero
Dans l'exemple suivant, la division par zéro est contrôlée par la fonction failwith qui déclenche l'exception pré-
définie Failure "division par zero".
#let a = 55 and x = 0 in
if x = 0 then failwith "division par zero" else a / x ;;
Uncaught exception: Failure "division par zero"
Contrôle au moyen de la fonction invalid_arg

controle_d'évaluation ::=

invalid_arg expression_chaine_message

Dans l'exemple suivant, le contrôle des valeurs admises est réalisé par
l'emploi de la fonction invalid_arg qui déclenche l'exception pré-définie
.Invalid_argument of string
#let feu = "VIOLET" in
if feu = "ROUGE" then "STOP"
else if feu = "ORANGE" then "RALENTIR"
else if feu = "VERT" then "PASSER"
else invalid_arg feu ;;
Uncaught exception: Invalid_argument "VIOLET"
Le type construit et le type produit
Le type construit
Définition d'un type construit simple

définition_type_construit ::=

type nom_type = constructeur_de_valeur

Exemple de type construit simple


#type unique = MONO ;;
Type unique defined.
#MONO ;;
- : unique = MONO
Dans cet exemple, MONO est un constructeur de valeur et unique est un type construit. L'évaluation de l'expression
MONO renvoie la valeur MONO dont le type correspond à unique. Le type unique , ainsi défini, ne comprend q'une
.seule valeur : la valeur MONO
Définition d'un type construit composé

définition_type_construit ::=

type nom_type = constructeur_de_valeur of type

Exemple de type construit composé


#type message = Message of string ;;
Type message defined.
#Message "fin de session" ;;
- : message = Message "fin de session"
Dans cet exemple, Message est un constructeur de valeur et message est un type construit. L'évaluation de
l'expression, Message "fin de session" renvoie la valeur Message "fin de session" dont le type
est message. Le type message, ainsi défini, rassemble toutes les valeurs composées avec le constructeur
.Message suivi d'une chaîne de caractère quelconque

Le type produit cartésien : les tuples


Les valeurs d'un type produit cartésien, appelées n-uplets ou tuples, sont formées par une juxtaposition de valeurs
.séparées par le constructeur de valeur virgule ",". Un tuple à deux éléments est aussi appelé paire
Syntaxe d'une expression de type produit

expression_de_type_produit ::=

expression_de_type_1 * expression_de_type_2 * ... * expression_de_type_n

Valeur d'une expression de type produit : tuple

valeur_tuple ::=
expression_1 , expression_2 , ... , expression_n

Quelques exemples d'expressions de type produit

Une paire formée d'un entier et d'une expression de valeur entière : int * int
#7,)9+4( ;;

- : int * int = 7, 13

Une paire mixte (chaîne de caractères, entier) : string * int


#"ZERO",0 ;;

- : string * int = "ZERO", 0

Un triplet : int * string * bool


#12, "Lucas", true ;;

- : int * string * bool = 12, "Lucas", true

Une paire de paires : (int * int) (bool * bool)


#)1,0(,)true,false( ;;

- : )int * int( * )bool * bool( = )1, 0(, )true, false(

Un quadruplet : int * int * bool * bool


#1,0,true,false ;;

- : int * int * bool * bool = 1, 0, true, false

Typage d'une expression de type produit

E1:T1 E2:T2 ... En:Tn

)E1, E2, ... , En(:T1 * T2 * ... * Tn

Le type enregistrement
Le type enregistrement est une structure composée de champs nommés par des étiquettes (noms de champs). Chaque
.champ peut contenir une valeur du type précisé dans la définition de la structure de l'enregistrement
Première approche du type enregistrement

enregistrement ::=
))étiquette_1, expression_1(,

)étiquette_2, expression_2(,

...

)étiquette_n, expression_n((

Dans ce cas, pour réaliser son implémentation, le type enregistrement est considéré comme un n_uplet de paires
(dans lequel chaque paire a pour expression de type (étiquette_i, expression_i

Exemple d’enregistrement selon la première approche

#)

)"nom_prenom", "LESCURE MARIE"(,

)"sexe", `F`(,

)"age", 10(

( ;;

- : )string * string( * )string * char( * )string * int( = )"nom_prenom",


"LESCURE MARIE"(, )"sexe", `F`(, )"age", 10(

Deuxième approche du type enregistrement

type t_etiq_1 = constructeur_1 of type_1

and t_etiq_2 = constructeur_2 of type_2

...

and t_etiq_n = constructeur_n of type_n

enregistrement ::=

)constructeur_1)expression_1_de_type_1(,

constructeur_2)expression_2_de_type_2(,

...

constructeur_n)expression_n_de_type_n(,

avec le typage de valeur suivant, val_i : t_etiq_i

Dans ce cas, le type enregistrement est considéré comme un n_uplet de types construits dont le typage correspond à :
t_etiq_i ou encore constructeur_i of type_i

Exemple d'enregistrement selon la deuxième approche

#type personne_label1 = Nom_prenom of string

and personne_label2 = Sexe of char

and personne_label3 = Age of int ;;

Type personne_label1 defined.

Type personne_label2 defined.

Type personne_label3 defined.

#)

Nom_prenom)"LESCURE MARIE"(,

Sexe")`F`(,

Age)10(

( ;;

- : personne_label1 * personne_label2 * personne_label3 = Nom_prenom "LESCURE


MARIE", Sexe `F`, Age 10

Syntaxe d'une définition de type enregistrement

type_enregistrement ::=

type nom_type = {

étiquette_1 : type_1;

étiquette_2 : type_2;

étiquette_n : type_n }

Syntaxe d'une définition d'enregistrement

définition_enregistrement ::= {

étiquette_1 = expression_1;
étiquette_2 = expression_2;

...

étiquette_n = expression_n }

.Remarque : L'ordre des champs est indifférent


Typage d'un enregistrement

E1:T1 ... En:Tn

{C1=E1;...;Cn=En(}:{C1:T1;...;Cn:Tn}

ou bien

E1:T1 ... En:Tn T={C1:T1;...;Cn:Tn}

{C1=E1;...;Cn=En(}:T

Exemples
#type personne =
{nom_prenom:string; sexe:char; age:int};;
Type personne defined.

)* définition de 2 enregistrements x et y
du type personne
*(
#let x = {
nom_prenom = "LESCURE MARIE";
sexe = `F`;
age = 10 } ;;
x : personne = {nom_prenom="LESCURE MARIE"; sexe=`F`;
age=10}
#let y = {
age = 12; sexe = `M`;
nom_prenom = "VALLEE JEAN"};;
y : personne = {nom_prenom="VALLEE JEAN"; sexe=`M`;
age=12}
Accès à un champ d'un enregistrement déterminé
Pour retrouver la valeur associé à un champ d'un enregistrement, on le désigne par l'identificateur de
.l'enregistrement suivi d'un point et de l'étiquette du champ

accès_champ_enregistrement ::=

identificateur_d'enregistrement.étiquette_de_champ

Exemples
)* accès aux champs de 2 enregistrements
x et y du type personne
*(
#x.nom_prenom ;;
- : string = "LESCURE MARIE"
#y.nom_prenom ;;
- : string = "VALLEE JEAN"
#x.sexe ;;
- : char = `F`
#y.age ;;
- : int = 12
Exercice 5
: Typer les expressions Caml suivantes
1. )c + 4( >= )8 - x(
2. )"a" ^ "b"( = c
3. )4 > 8( = )"a" = "b"(
4. )"a" + 5( = )"a" + 5(

Solution

Type et valeur des expressions


Définitions et environnement
Exercice 6
En utilisant les définitions emboîtées en Caml, et avec x=5, calculer
: l'expression mathématique
A = x5 - 2x4 + 3x3 - 4x2 + 5x - 6

Solution

Définitions et environnement
Exercice 7
: Dans un environnement Eo, on effectue la définition
#let taux = 2 in
let alpha = 5 in
let coef = taux * alpha + alpha in
let a = taux * alpha + coef * alpha;;
? Décrire le nouvel environnement. Quel est le résultat affiché
Solution

Type et valeur des expressions


Définitions et environnement

Les fonctions
Fonctions à une variable et fonctions à un argument
.La variable est placée en argument de la fonction. Cet argument est du type de la variab
yntaxe des fonctions à une variable

expression_fonctionnelle ::=

function variable -> expression

Typage des fonctions à une variable

V:T1 E:T2

function V->E:T1->T2

Fonctions à plusieurs variables et fonctions à un argument


Les variables sont réunies en un seul argument de la fonction et cet argument est du type produit cartésien composé
.à partir du type de chaque variable
Syntaxe des fonctions à plusieurs variables

expression_fonctionnelle ::=

function)var_1,...,var_n( -> expression

Typage des fonctions à plusieurs variables


function )V1,...,Vn(->E:)T1*...*Tn(->T

Fonctions à plusieurs variables et fonctions à plusieurs arguments


Les variables sont disposées comme autant d'arguments de la fonction. Chaque argument est du type de la variable
.qu'il représente
Syntaxe des fonctions à plusieurs variables

expression_fonctionnelle ::=

function var_1 ->

function var_2 ->

function var_n -> expression

Typage des fonctions à plusieurs variables

V1:T1 ... Vn:Tn E:T

function V1->...->function Vn->E:T1->...->Tn->T

Exemples de définition de fonction


On veut définir une fonction est_pair en Caml, telle qu'elle reçoive un entier n en argument et retourne en résultat,
.true si n est pair, sinon false
Type de la fonction est_pair : int -> bool

: 1ère solution
On construit une solution au problème en faisant appel à une fonction reste(a,b) qui nous retourne le reste de la
.division entière de a par b
let reste =
function )a,b( -> let q = a / b in a - b * q ;;
let est_pair =
function n -> if reste)n,2( = 0 then true else false ;;
: 2ème solution
.On utilisera de préférence l'opérateur arithmétique mod pré-défini à la place de la fonction reste
let est_pair =
function n -> if n mod 2 = 0 then true else false ;;
: 3ème solution
On remarque que si
)A = )if n mod 2 = 0 then true else false
)B = )n mod 2 = 0
alors, l'expression A et l'expression B sont équivalentes. En effet, si B vaut true, A retourne true, et si B est évaluée à
false, alors A = false

.En conséquence, on peut réécrire la fonction est_pair en utilisant B au lieu de A


: Cela donne la fonction simplifiée
let est_pair = function n -> n mod 2 = 0 ;;

Fonctions anonymes
Une fonction anonyme est une expression fonctionnelle. Ainsi l'expression fonctionnelle : function var -> expr, de
« type fonctionnel : T1 -> T2, est une fonction anonyme. Elle a pour valeur fonctionnelle «x~>expr(x),Edéf
Evaluation de l'application d'une fonction anonyme
: E étant une expression du type T1 de valeur val, on évalue l'application de cette fonction anonyme à l'expression E

(Evaluation((function var -> expr) E


(Evaluation(«x~>expr(x),Edéf » val <=
(« Evaluation(«expr(val),Edéf <=
r <=

,En conséquence
Evaluation((function var -> expr) E) : T2 = r

Fonctions nommées
Une fonction nommée fait l'objet d'une définition formant une liaison (identificateur, valeur fonctionnelle). Ainsi,
dans la définition : let ident_f = function var -> expr , l'identificateur ident_f désigne une fonction
« nommée de type fonctionnel : T1 -> T2 , qui a pour valeur fonctionnelle «x~>expr(x);Edéf
Evaluation de l'application d'une fonction nommée
On évalue l'application de la fonction ident_f à l'expression E

(Evaluation(ident_f E
(Evaluation(«x~>expr(x);Edéf » val <=
(« Evaluation(«expr(val);Edéf <=
r <=

,En conséquence
Evaluation(ident_f E) : T2 = r

: Remarque
Si Evaluation((function var -> expr) E) : T2 = r
et Evaluation(ident_f E) : T2 = r
: on en déduit que
function var -> expr) = ident_f)

En conséquence, dans les expressions Caml, on peut remplacer le nom d'une fonction par une expression
.fonctionnelle équivalente et réciproquement

Définitions de fonctions nommées


Syntaxe 1ère forme
Fonction à un argument

définition_fonctionnelle ::=
let identificateur =

function variable -> expression

Fonction à plusieurs arguments

définition_fonctionnelle ::=

let identificateur =

function var_1 ->

function var_2 ->

...

function var_n -> expression

Syntaxe 2ème forme

Fonction à un argument

définition_fonctionnelle ::=

let identificateur variable = expression

Fonction à plusieurs arguments

définition_fonctionnelle ::=

let ident var_1 var_2 ... var_n = expression

Syntaxe 3ème forme

Fonction à un argument

définition_fonctionnelle ::=

let identificateur)variable(=expression

Fonction à plusieurs arguments

définition_fonctionnelle ::=

let ident)var_1()var_2(...)var_n(= expression

Syntaxe des fonctions 4ème forme

Fonction à un argument

définition_fonctionnelle ::=

let identificateur = fun variable -> expression


Fonction à plusieurs arguments

définition_fonctionnelle ::=

let identificateur =

fun var_1 var_2 ... var_n -> expression

Exemples
let cube = function x -> x * x * x
let cube x = x * x * x
let cube)x(= x * x * x
let cube = fun x -> x * x * x
Exemples (fonctions à plusieurs arguments)

let paire =
function x ->
function y -> )x,y(
let paire x y = )x,y(
let paire)x()y(=)x,y(
let paire = fun x -> fun y -> )x,y(
Evaluation d'une définition de fonction
La définition d'une fonction construit une liaison (identificateur, fermeture) dans l'environnement temporaire s'il
.s'agit d'une définition locale ou dans l'environnement global s'il s'agit d'une définition globale

Variables liées et variables libres


Soit un environnement dans lequel la liaison (y, 8) est accessible, on considère la fonction suivante : function x
-> 2 * x + 5 * y, alors x est une variable liée dans la fonction, tandis que y est une variable libre dans la
.fonction. La variable libre y est définie par une liaison à un niveau global par rapport à la fonction

Exemples de typage des fonctions


Fonction du type : int -> int -> int
)* définition *(
let add = function a -> function b -> a + b ;;
)* application *(
add 2 5 ;;
Fonction du type : int -> (int -> int)
)* définition *(
let g = function u -> )function v -> u + v( ;;
)* application *(
g 2 5 ;;
Fonction du type : (int -> int) -> int
)* définition *(
let f = function e -> 1+ e)1+ e)1(( ;;
)* application *(
f )add 1( ;;
f )g 1(;;
Fonction du type : (int -> int) -> (int -> int)
)* définition *(
let h = function k -> )function a -> k)a+ 1(+ 1( ;;
)* application *(
h )add 1( 1;;
h )g 1(;;
f )h )add 1( (;;
f )h )g 1( (;;

Evaluation d'une fonction, fermeture, valeur fonctionnelle


Une fermeture dénote une valeur fonctionnelle c'est-à-dire un couple formé par le code de la fonction et son
environnement de définition. Ainsi, pour une fonction décrite par function x -> f)x(, sa fermeture sera
notée : F = «x~>f)x(, Ef_définition», où x~>f)x( signifie le code de la fonction (premier membre du
couple), et Ef_définition est l'environnement courant au moment de la définition de la fonction (deuxième
.(membre du couple

Fonctions partielles
Les fonctions partielles sont de fonctions non totalement définies sur l'ensemble des valeurs du type correspondant à
.l'ensemble de définition
Cas de la fonction inverse
#let inverse x = 1.0 /. x ;;
inverse : float -> float = >fun>
#inverse 5.0 ;;
- : float = 0.2
#inverse 0.0 ;;
80387 Exception: divide by zero!
- : float = 0.9999976515814
Dans le cas traité en exemple, la fonction n'étant pas définie pour la valeur 0.0 de l'argument, l'exécution du
.programme conduit à une terminaison anormale de l'évaluation de l'application de la fonction à cette valeur

Pour éviter ce problème, le programmeur a la ressource de construire un type nouveau correspondant précisément à
l'ensemble des valeurs pour lesquelles la fonction est définie. Toutefois, il n'est pas toujours possible de définir le
type souhaité. Il faut alors intercepter (cf. filtrage) les valeurs pour lesquelles la fonction n'est pas définie et leur
appliquer un traitement particulier (cf. exceptions). Ainsi la fonction partielle peut être transformée en fonction
.totale

Remarque : Les spécifications de Caml ne définissent pas le traitement du débordement des opérations sur le type
float. Selon la machine utilisée, une division par 0.0 pourrait avoir des résultats très différents, du simple
.déclenchement d'une exception à l'arrêt de la machine

Types fonctionnels
Les types fonctionnels sont de la forme T1->T2 dans laquelle T1 et T2 peuvent être de n'importe quel type, y
.compris les types fonctionnels

Exemples de types fonctionnels


int -> int
int -> int -> bool )* qui est équivalent à : int -> )int ->
bool( *(
)string -> int( -> char
)'a -> 'b( -> )'c -> 'd( )* type fonctionnel polymorphe *(

Les applications
.Une application est une expression formée d'une fonction associée à un ou plusieurs de ses arguments
Syntaxe des applications
application d'une fonction à un argument

expression_applicative ::=

expression_f expression_p

Si expression_applicative est une application d'une fonction quelconque f,


alors expression_f est une expression descriptive de la valeur fonctionnelle
correspondant à la fonction f et expression_p est une expression descriptive
d'une valeur fournie comme paramètre effectif de la fonction f. Chacune des
deux expressions peut être placée entre parenthèses pour lever toute
.ambiguité éventuelle
application d'une fonction à plusieurs arguments

expression_applicative ::=

expression_f expression_1 ... expression_n

Considérant que expression_applicative est une application d'une fonction


quelconque f, alors expression_f est une expression descriptive de la valeur
fonctionnelle correspondant à la fonction f et les expression_i sont des
expressions descriptives des valeurs fournies comme paramètres effectifs de
.la fonction f
Typage des applications
Si E est une expression décrivant une fonction de type T1->T2, et si E' est une expression décrivant une valeur de
type T1, alors l'application de E à E' (qui s'écrit E E') est correctement typée T2. Cette règle peut être exprimée par la
: notation suivante

E:T1->T2 E':T1

Evaluation d'une application


: Règle du passage des paramètres
les paramètres effectifs de l'application sont évalués préalablement à leur substitution aux paramètres formels de la
.fonction

.L'évaluation de l'application est réalisé dans l'environnement de définition de la fonction


Applications partielles
Soit la fonction à deux arguments enchaine qui concatène deux chaînes de caractères s1 et s2 pour donner une
: chaîne en résultat
;; let enchaine s1 s2 = s1 ^ s2#
>enchaine : string -> string -> string = >fun
: Considérons les cas suivants
,une application totale de cette fonction, quand les deux arguments sont fournis (1
;; "enchaine "Auteur : " "Richard E. Pattis#
"string = "Auteur : Richard E. Pattis : -
,une application partielle de cette fonction, quand un seul argument est fourni (2
;; " : enchaine "Titre#
>string -> string = >fun : -
.l'évaluation de l'application renvoie une valeur fonctionnelle dont le type correspond à une fonction à un argument

: Ainsi, à partir de l'application partielle d'une fonction, nous pouvons définir une série de nouvelles fonctions
;; " : let rubrique_titre = enchaine "Titre#
>rubrique_titre : string -> string = >fun
.l'identificateur rubrique_titre est lié à la valeur fonctionnelle créée par l'application partielle de la fonction
;; "rubrique_titre "Karel The Robot#
"string = "Titre : Karel The Robot : -
Exercice 8
.Au cours d'une session Caml, E est l'environnement initial
Typer, évaluer les phrases Caml suivantes et indiquer l'environnement
: résultant
1. # let a = 5 ;;
2. # let a = a + a ;;
3. # let v = )a = 10( ;;
4. # let f = function x -> x*x + a*a ;;
5. # f 2 ;;
6. # f f 2 ;;
7. # let rec h = function
0 -> 1
| 1 -> 1
| n -> )f)n-2( + 1( * f)n-1( ;;
8. # h 7 ;;
9. # let gamma =
function a -> function b -> a*b ;;
10.# let z = gamma 5 ;;
11.# gamma 8 4 ;;
12.# z )z 2( ;;
Solution

Type et valeur des expressions


Définitions et environnement
Fonctions
Exercice 9
: Typer, évaluer les phrases Caml suivantes
1. # let Y = function x -> function y -> function z -> y ;;

2. # let H = function u -> function x -> u x x ;;

3. # H )function x -> fun y -> x+y( 4 ;;


Solution

Type et valeur des expressions


Définitions et environnement
Fonctions
Exercice 10
Au cours d'une session Caml, Env est l'environnement initial, et les
: définitions suivantes sont effectuées
1(#let a = 5 ;;
2(#let b = 3 ;;
3(#a,b ;;
4(#let alpha x = let a = 2 in a * x + b ;;
5(#alpha 7 ;;
6(#let béta x = let b = 2 in a * x + b ;;
7(#béta 7 ;;
8(#let gamma a b = let x = 7 in a * x + b ;;
9(#gamma a b ;;
10(#let a,b,x = 2,1,3 ;;
11(#alpha x , béta x , gamma a b ;;
Evaluer et typer chacune des définitions )1
Décrire l'évolution de l'environnement à chaque étape )2
Décrire les fermetures des fonctions )3

Solution

Type et valeur des expressions


Définitions et environnement
Fonctions
Exercice 11
: Typer et évaluer les définitions Caml suivantes
1( #let h = function f -> function g -> g f ;;

2( #let x = h 4 ;;
3( #let t = h 4 )function x -> x + 2( ;;
Solution

Type et valeur des expressions


Définitions et environnement
Fonctions
Exercice 12
: Déclarer les fonctions suivantes en Caml
)Fonction suivant : à un entier n on fait correspondre l'entier )n+1 .1
)Fonction precedent : à un entier n on fait correspondre l'entier )n-1 .2
Fonction double : à un entier n on fait correspondre l'entier 2*n .3

Solution

Définitions et environnement
Fonctions
Exercice 13
Construire, en Caml, la fonction base permettant de calculer la valeur de
base de décompte selon la règle de gestion :

Si le plafond est inférieur au salaire,

alors la base de décompte est égale au plafond,

sinon la base de décompte est égale au salaire.


Syntaxe = base salaire plafond
Typage = base : int -> int -> int

Solution

Type et valeur des expressions


Expressions conditionnelles
Fonctions

Retour au début du document

dernière modification : 03/03/99

Vous aimerez peut-être aussi