EPITA Spé: Programmation Introduction à OCaml - wiki-prog

publicité
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
EPITA Spé: Programmation
Introduction à OCaml
Marwan Burelle
[email protected]
http://wiki-prog.kh405.free.fr
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Plan
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
1
Introduction
Introduction
Architecture des
programmes
OCaml
2
Architecture des programmes OCaml
3
Programmation Fonctionnelle
4
Programmation Impérative en OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Introduction
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Introduction
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Objective Caml
EPITA Spé:
Programmation
Introduction à
OCaml
Langage fonctionnel de la famille ML
Langage fortement typée, doté d’un typage statique
Le système de type propose un mécannisme
d’inférence (type reconstruction)
Le système de type est polymorphe
Le langage dispose de l’ordre supérieur
Le langage propose des extensions impératives
Le langage propose un sous-langage de modules très
évolué (modules imbriqués, foncteurs . . . )
Le langage propose un couche objet
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Programmation Fonctionnelle
EPITA Spé:
Programmation
Introduction à
OCaml
Pas de notion variables
Itérations au travers de la récursion
Marwan Burelle
Introduction
Les fonctions sont le point centrale du langage
Architecture des
programmes
OCaml
Généricité au travers des fonctions de première classe
et du polymorphisme
Programmation
Fonctionnelle
Pas d’instruction : tout est expression et renvoie une
valeur
Pas d’effet de bord
Les opérations sur une structure de donnée travaille
toujours en renvoyant une copie.
Programmation
Impérative en
OCaml
Architecture des programmes OCaml
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes OCaml
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Architecture Générale
En règle général, un programme OCaml est composé
d’une série de définition et de bloc de code à exécuter.
Tout est exécuté : il n’y a pas de véritable différence
entre une définition et un bloc de code exécuté.
Example:
(* Exemple de programme OCaml *)
(* Definition de fonction *)
let f x = x
(* Blocs de code *)
let y =
begin
print_string " Definition de la constante y\n";
10
end
let toto = ( print_int y; print_int f y; print_newline ())
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Point d’entrée
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Il n’y a pas de notion de point d’entrée puisque tout le
code est exécuté.
Attention, exécuter ne signifie pas que le résultat sera
visible !
Les définitions ne sont pas différentiées des blocs de
code simples, le corps de la définition est exécuté et sa
valeur résultat est associée au symbole définie.
On utilise généralement le motif universel " " pour
indiquer que le résultat ne sera pas réutilisé (pas de
symbole créé.)
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Organisation Concrète
En règle général, un programme OCaml se compose
comme suit :
Une série de définition de constantes ;
Une série de définition de fonctions ;
Une fonction particulière qui servira de point d’entrée ;
Un bloc de code appelant la fonction principale.
Example:
(* Constantes *)
let pi = acos ( -1.)
(* Fonctions *)
let surface_cercle r = 2. *. pi *. r *. r
(* Point d’ entree *)
let main () =
let r = int_of_string ( Sys .argv .(1)) in
print_float ( surface_cercle r)
(* Appel du point d’ entree *)
let _ = main ()
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Compilation v.s. Interprétation
L’interpréteur affiche un résultat pour toutes les phrases
entrées :
# 1+1 ;;
- : int = 2
Les phrases composées uniquement d’une expression,
bien qu’elles soient exécutées, n’ont pas d’effet visisble
dans un programme compilé :
# echo " 1+1;; " > toto.ml
# ocamlc -o toto toto.ml
# ./ toto
#
On évitera l’utilisation des ”;;”
Un bloc de code qui ne renvoie rien (affichage, bloc
impératif . . . ) sera introduit par une construction :
let _ = ...
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Un programme complet
Example:
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
(* Exemple de programme en OCaml *)
Introduction
(* Les constantes *)
let pi = acos ( -1.)
(* Les fonctions *)
let surface r = 2. *. pi *. r *. r
(* Fonction principale *)
let main () =
begin
print_string "Rayon du cercle ?\n";
let r = read_float () in
print_string " Surface du cercle de rayon ";
print_float r;
print_string " = ";
print_float ( surface r);
print_newline ();
end
(* Appel *)
let _ = main ()
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Programmation Fonctionnelle
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation Fonctionnelle
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Typage et Inférence
EPITA Spé:
Programmation
Introduction à
OCaml
Le typage doit être respecté
OCaml est capable de déduire tout seul le type des
fonctions.
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Example:
Programmation
Fonctionnelle
# 1 + true ;;
This expression has type bool but is here used with type int
# let f x = x + 1;;
val f : int -> int = <fun >
# let f x = x;;
val f : ’a -> ’a = <fun >
# let f g x = (x+1,g x);;
val f : (int -> ’a) -> int -> int * ’a = <fun >
# f string_of_int 3;;
- : int * string = (4, "3")
Programmation
Impérative en
OCaml
Récursivité
Example:
Fichier fact.ml :
let rec fact = function
0 | 1 -> 1
| x when x >0 -> x * fact (x -1)
| _ -> assert false
let main () =
begin
let x = int_of_string ( Sys .argv .(1)) in
print_int (fact x);
print_newline ();
end
let _ = main ()
Compilation et exécution :
$ ocamlc -o fact fact.ml
$ ./ fact 6
720
$ ./ fact 10
3628800
$ ./ fact 12
479001600
$
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Listes
’a list
Constructeurs :
[] liste vide
:: ajout en tête
Opération :
@ concaténation
Example:
#
#
#
#
#
[];;
: ’a list = []
1::[];;
: int list = [1]
[1;2];;
: int list = [1; 2]
[1;2] @ [3;4];;
: int list = [1; 2; 3; 4]
let rec length = function
[]
-> 0
| _::t -> 1 + length t;;
val length : ’a list -> int = <fun >
# length [1;2;3];;
- : int = 3
#
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Ordre Supérieur
Example:
# let rec map f = function
[] -> []
| h::t -> (f h):: map f t;;
val map : (’a -> ’b) -> ’a list -> ’b list = <fun >
# let rec fold f a = function
[] -> a
| h::t -> fold f (f a h) t;;
val fold : (’a -> ’b -> ’a) -> ’a -> ’b list -> ’a = <fun >
# map float_of_int [1;2;3];;
- : float list = [1.; 2.; 3.]
# fold (+) 0 [1;2;3];;
- : int = 6
# fold (fun a x -> x::a) [] [1;2;3;4;5;6;7];;
- : int list = [7; 6; 5; 4; 3; 2; 1]
#
Fichier print list.ml :
let rec iter f = function
[] -> ()
| h::t -> f h; iter f t
let maliste = [1;2;3;4;5;6;7]
let main () =
iter (fun x -> P r i n t f . printf " %i;" x) maliste ; print_newline ()
let _ = main ()
$ ocamlc -o print_list print_list .ml
$ ./ print_list
1; 2; 3; 4; 5; 6; 7;
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Types Sommes
Example:
type ’a tree =
Leaf of ’a
| Node of ’a tree * ’a * ’a tree
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
let rec find x = function
Leaf c | Node(_,c,_) when x = c -> true
| Node(fg ,_,fd) ->
(find x fg) || (find x fd)
| _ -> false
let rec list_of_tree = function
Leaf c -> [c]
| Node(fg ,c,fd) ->
( list_of_tree fg)@[c]@( list_of_tree fd)
let arbre =
Node(Node(Leaf 1,2, Leaf 3),4,
Node(Leaf 5,6, Leaf 7))
let main () =
begin
L i s t .iter (fun x -> P r i n t f . printf "%i;" x) ( list_of_tree arbre );
print_newline ();
print_string (if (find 5 arbre) then " trouve !\n"
else "pas trouve !\n");
end
let _ = main ()
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Algortithmes et programmation fonctionnelle
EPITA Spé:
Programmation
Introduction à
OCaml
Prennons le cas de listes triées d’entiers :
elem = 0
elem = 3
elem = 6
Marwan Burelle
Introduction
Nous allons insérer de manière fonctionnelle la valeur 2
dans la liste :
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
elem = 0
elem = 0
elem = 3
elem = 6
elem = 2
Si les choses sont faites correctement, la fin de la liste (qui
n’est pas modifiée) est partagée entre l’ancienne liste (qui
demeure inchangée) et la nouvelle. Pour plus de détail
référez vous aux slides du premier cours.
Programmation
Impérative en
OCaml
Programmation Impérative en OCaml
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Programmation Impérative en
OCaml
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Essayons de faire des boucles
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Example:
Introduction
(* Boucles qui ne marchent pas ... *)
let _ =
let x = 10 in
while (x <0) do
print_int x;
let x = x - 1 in (* ? *) ()
done
La construction let x = ... in ... définie un nouveaux symbole
x à chaque fois. On voudrait modifier la valeur de x à chaque
tour de boucle, ce qui est incohérent avec la programmation
fonctionnelle.
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Données modifiables
EPITA Spé:
Programmation
Introduction à
OCaml
Pour faire de la programmation impérative, il faut
pouvoir modifier certaines données.
Comment peut-on être fonctionnel et avoir des
variables ?
Idée : la donnée manipulée reste constante, mais on
dispose d’un mécannisme d’accès pour la modifier.
On parle de donnée muable (terme horrible en français,
mais modifiable est un peu trop faible.)
En OCaml, il existe plusieurs sortes de données
muable : les références (pointeurs statiques), les
champs d’enregistrements, les (cases des) tableaux,
les chaı̂nes de caractères et les propriétés des objets.
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Les références
Une référence est une sorte de pointeur, la valeur d’une
référence est immuable, mais cette valeur est une
adresse sur une valeur que l’on pourra modifier.
Le polymorphisme sur les références est limité (les
changements de valeur référencée doivent préserver le
type d’origine.)
Une référence pointe toujours sur une valeur (pas de
problème de pointeur null.)
Example:
# let r = ref 0;;
val r : int ref = { contents = 0}
# !r;;
- : int = 0
# (r := 2; !r);;
- : int = 2
# r := "a" ;;
This expression has type string but is here used with type int
#
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Polymorphisme et références
Example:
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
# let f x = x ;;
val f : ’a -> ’a = <fun >
# let r = ref f ;;
val r : (’_a -> ’_a) ref = { contents = <fun >}
# !r;;
- : ’_a -> ’_a = <fun >
(* ’_a is not a polymorphic type variable *)
# (!r) 1;;
- : int = 1
# !r;;
- : int -> int = <fun >
(* r is now a reference to a int -> int function *)
# f true ;;
- : bool = true
# (!r) true ;;
This expression has type bool but is here used with type int
# r := fun x -> x + 1 ;;
- : unit = ()
# !r 1;;
- : int = 2
#
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Les tableaux
Example:
# let t = [| 1; 2; 3 |];;
val t : int array = [|1; 2; 3|]
# t .(0);;
- : int = 1
# t.(0) <- 2;;
- : unit = ()
# t .(0);;
- : int = 2
# let f x = Array .make 10 x;;
val f : ’a -> ’a array = <fun >
# f true ;;
- : bool array =
[| true; true; true; true; true; true; true; true; true; true |]
# let t2 = f (ref 0);;
val t2 : int ref array =
[|{ contents = 0}; { contents = 0}; { contents = 0}; { contents = 0};
{ contents = 0}; { contents = 0}; { contents = 0}; { contents = 0};
{ contents = 0}; { contents = 0}|]
# t2 .(0) := 1 ;;
- : unit = ()
# t2 ;;
- : int ref array =
[|{ contents = 1}; { contents = 1}; { contents = 1}; { contents = 1};
{ contents = 1}; { contents = 1}; { contents = 1}; { contents = 1};
{ contents = 1}; { contents = 1}|]
#
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Les enregistrements
Example:
# type r = { a : int; mutable b : string } ;;
type r = { a : int; mutable b : string ; }
# let x = { a = 0; b = "" };;
val x : r = {a = 0; b = ""}
# x.b <- " bonjour " ;;
- : unit = ()
# x;;
- : r = {a = 0; b = " bonjour "}
# let y = { x with a = 1 };;
val y : r = {a = 1; b = " bonjour "}
# x.b <- " bonjour2 " ;;
- : unit = ()
# y;;
- : r = {a = 1; b = " bonjour "}
Example:
# type r’ = { a : int ref; b : int };;
type r’ = { a : int ref; b : int; }
# let x = {a = ref 0; b = 1 };;
val x : r’ = {a = { contents = 0}; b = 1}
# let y = { x with b = 2 };;
val y : r’ = {a = { contents = 0}; b = 2}
# x.a := 1; y ;;
- : r’ = {a = { contents = 1}; b = 2}
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Les chaı̂nes de caractères
Example:
# let s = " bonjour ";;
val s : string = " bonjour "
# s.[7] = ’\n ’;;
- : bool = false
# s.[7] <- ’\n ’;;
- : unit = ()
# s;;
- : string = " bonjour \n"
Example:
let maj s =
for x = 0 to ( String . length s) - 1 do
s.[x] <- Char. uppercase (s.[x])
done
let main () =
let s = String .copy Sys .argv .(1) in
maj s;
print_string s;
print_newline () ;
exit 0
let _ = main ()
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Le retour des boucles
Example:
let fibbo n =
let i = ref 1 in
let fib1 = ref 1 in
let fib2 = ref 1 in
while (!i < n) do
fib1 := !fib1 + !fib2;
fib2 := !fib1 - !fib2;
i := !i + 1
done ; !fib1
let rec fib = function
0|1 -> 1
| n -> (fib (n -1)) + (fib (n -2))
let main () =
let i = read_int () in
P r i n t f . printf "par boucle : %i, par rec: %i\n" (fibbo i) (fib i);
exit 0
let _ = main ()
EPITA Spé:
Programmation
Introduction à
OCaml
Marwan Burelle
Introduction
Architecture des
programmes
OCaml
Programmation
Fonctionnelle
Programmation
Impérative en
OCaml
Téléchargement