TUTORIEL OCAML



Présentation

1
Types

2
Operateurs

3
Fonctions

4
Récursivité

5
Listes

6
Enregistrement
et
Types Sommes

7
Annexes


Exercices


Corrections


Les Enregistrements et les Types Sommes

Faisons un petit bilan, voulez-vous ? Nous savons manipuler des variables, créer des fonctions (récursives et non récursives), stocker des valeurs dans des listes ... Bon c'est très bien, mais sachez que l'on peut faire encore plus (Eh oui, vous en doutiez n'est-ce pas ^_^ ?). Vous ne me croyez pas ? Eh bien posez vous des questions sur vos futurs programmes ! Si jamais on vous demande de créer un jeu, par exemple, dans lequel le joueur incarne un personnage qui aura des caractéristiques propres à son évolution, comment allez-vous créer ce personnage ?
Vous apprendrez ici une notion très importante qui vous servira dans d'autres langages de programmation:

Les Enregistrements et Les Types Somme.

Pour faire simple, on va créer nos propres types. Voici un exemple de type pour un personnage de jeu:
 Nom: KuK
 Age: 20 ans
 Métier: Astronaute
 Statut: Robot
 Initial: k
 Autre: J'aime les frites

type t_perso = {nom : string; age : int; initial : char; metier : string; statut : string; autre : string};;
type t_perso = {
 nom : string;
 age : int;
 initial : char;
 metier : string;
 statut : string;
 autre : string
}

let heros = {nom = "KuK"; age = 20; initial = 'k'; metier = "Astronaute"; statut = "Robot"; autre = "J'aime les frites"};;

Ceci peut servir de début de code pour un jeu dont le héros (MOI 8-) ) a plusieurs caractéristiques (on appelle ça des champs, nom, age, lettre, ...). Chaque champs a un type qui a déjà été défini (int, float, char, string, mais également des types que vous aurez vous-même créé).
Désormais, quand je parlerai [[http:www.ramytemim.com/doku.php?id=tutorielocaml:ocaml1|des variables]] que nous avons vues au tout début de ce tutoriel je dirai "variables de type classique".

Les Enregistrements

Mise en place

Pour construire un enregistrement, il suffit de:

type nomDuType = { champs1 : type1 ; champs2 : type2 ; champs3 : type3 . . .} ;;

type1, type2, type3 sont trois types de variables classiques.

Vous aussi vous êtes étudiant ? Créez votre propre type :-) !

type t_etudiant = {nom : string; prenom : string; age : int; annee : int};;


t_etudiant est maintenant un type. Il est constituer de 4 champs nom, prenom, age et annee. Pour créer une variable de type etudiant:

let tartempion = {nom = "Empion" ; prenom = "Tart" ; age = 15; annee = 5};;

Pour mieux vous y retrouver au début, je vous conseille d'utiliser la notation t_nomenregistrement. Même si cela n'est pas obligatoire, cela peut aider (notamment grâce à la présence du "t_" qui permet d'indiquer que c'est un enregistrement).

Accéder a la Valeur d'un Champ

Accès

on a notre étudiant tartempion de type t_etudiant, si je veux accéder à son prénom:

tartempion.prenom;; - : string = "Tart"

...à son age:

tartempion.age;; - : int = 15

...à son année:

tartempion.annee;; - : int = 5

D'une manière générale, vous utiliserez cette sytntaxe:

nomVariable.champs;; (* nomVariable est une variable d'un type que vous aurez créé, comme t_etudiant *)


1ère méthode :

Si vous voulez modifier la valeur d'un champs de votre type t_etudiant il va falloir réécrire notre type:

type t_etudiant = {mutable nom : string; mutable prenom : string; mutable age : int; mutable annee : int};;

Sachez que vous ne pourrez pas faire de modification tant qu'il n'y a pas ce mutable devant chaque champs !
Maintenant, passons à la syntaxe :

nomVariable.champs <- nouvelleValeur;;


tartempion.prenom <- tartempion.prenom ^ "e";;
- : unit = ()

tartempion.prenom;;
- : string = "Tarte"

tartempion.age <- 21;;
- : unit = ()

tartempion.age;;
- : int = 21


2ème méthode : On définit une fonction qui prend en paramètre un étudiant et qui modifie la valeur d'un champ:

let incrementeAge etudiant = {nom = etudiant.nom; prenom = etudiant.prenom ; age = etudiant.age + 1; annee = etudiant.annee};;
val incrementeAge : etudiant -> etudiant =

La fonction incrementeAge prend en paramètre un etudiant A et renvoie un etudiant B dont les valeurs de chaque champs utilise celle de A.
Je vous conseille d'utiliser la première méthode qui je trouve plus pratique !

Les Enregistrements et la Récursivité

Comme l'indique ce titre, la récursivité fait son grand retour (même si elle ne nous aura pas quittés très longtemps). Mais cette fois-ci, point de rec ou de condition d'arrêt, juste des enregistrements possédant des champs qui sont constitués d'enregistrement qui sont qui sont eux-mêmes constitués d'enregistrements ! Afin de se faire une idée plus précise, rien de tel qu'un schéma :

Ne vous inquiétez pas, ça se fait presque instinctivement:

type t_note = {maths : float; programmation : float; assiduite : float};;
type t_etudiant = {nom : string; prenom : string; age : int; annee : int; note : t_note};;

let moi = {nom = "KuK"; prenom = "KuK"; age = 20; annee = 1; note = {maths = 5.; programmation = 18.; assiduite = 12.} };;

Bon c'est super :-| ! Mais vous devriez vous demander comment accéder aux valeurs de maths, programmation et assiduite ! Vous ne vous posiez pas cette question :-D ?

moi.note;;
- : t_note = {maths = 5.; programmation = 18.; assiduite = 12.}

moi.note.maths;;
- : float = 5.

moi.note.programmation;;
- : float = 18.


Les Types Sommes

L'utilisation à la fois des Enregistrements (que vous savez utiliser maintenant) et des Types Sommes s'avère très efficace. Ces nouveaux types permettent de créer vos propres types, sauf que les valeurs de ces types sont plus limitées.

Les jours de la semaine:
 Lundi
 Mardi
 ...
 Samedi
 Dimanche.

On pourrait créer un type t_semaine dont les valeurs possibles ne seraient que celles ci-dessus.

type t_semaine =
 |Lundi
 |Mardi
 |Mercredi (* Voilà notre semaine *)
 |Jeudi
 |Vendredi
 |Samedi
 |Dimanche;;

let jour1 = Lundi;;
val jour1 : t_semaine = Lundi (* Ocaml reconnaît Lundi qui est de type t_semaine *)

Mise en place :

type t_montypesomme =
 |Element1
 |Element2
 | ...
 |Element15;;

Tout comme un enregistrement, on peut utiliser "t_"en préfixe par convention. Passons maintenant au cœur du problème. Les éléments en majuscules sont ce qu'on appelle des constructeurs : ils vont permettre de construire des variables de type t_montypesomme.

Nous avons déjà vu plusieurs exemples de constructeurs.
Par exemple, la virgule (,) permet de construire des n-uplets.
De même, les "::" permettent de construire une liste avec un élément et une liste de même type que cet élément.
Il en existe encore quelques autres que je ne citerai pas (vous pouvez faire un léger effort pour vous en rappeler :-).

Un petit exemple :

type t_specialite =
 |Mathematiques
 |Informatique
 |Biologie (* On pourrait ajouter un champs spécialité à notre type t_etudiant pour mieux caractériser nos étudiants *)
 |Medecine
 |Menage;;

Chaque constructeur s'écrit avec une MAJUSCULE !!!!

Les constructeurs avec Arguments

Comme le nom de cette partie l'indique, on peut créer un type somme avec des constructeurs acceptant des arguments. Pour cela il suffit d'ajouter le mot clé of derrière le constructeur ainsi que le type de l'argument.

type t_somme =
 |Constructeur1 of type1
 |Constructeur2 of type2
 |Constructeur3 of type3
 |... ;;

Ça permet tout simplement de préciser que tel constructeur sera d'un type précis. Voici le type t_note définit avec des constructeurs d'arguments:

type t_note =
 |Maths of float
 |Programmation of float;;


Voilà c'est tout ce que vous avez à savoir sur les Enregistrements et les Types Sommes.


Gros Exemple

Avant de se dire au revoir, on va amélioré notre type t_etudiant !

type t_occupation = |Sport |Job |Etude |Geeker |Manger |Facebook |Rien;;
type t_machine = |Pc |Mac |Machine_a_remonter_le_temps;;

type t_note = {maths : float; programmation : float; assiduite : float};;
type t_config = {machine : t_machine; ram : int; rom : int};;

type t_etudiant = {
 nom : string;
 prenom : string;
 age : int;
 note : t_note;
 occupation : t_occupation;
 ordi : t_config
};;

(* On définit un etudiant1 *)
let etudiant1 = {
 nom = "KuK";
 prenom = "KuK";
 age = 20;
 note = {maths = 5.; programmation = 18.; assiduite = 12.};
 occupation = Sport;
 ordi = {machine = Pc; ram = 4096; rom = 350000}
};;

(* On définit un etudiant2 *)
let etudiant2 = {
 nom = "Tarte";
 prenom = "Empion";
 age = 15;
 note = {maths = 10.; programmation = 5.; assiduite = 20.};
 occupation = Facebook;
 ordi = {machine = Mac; ram = 2048; rom = 350000}
};;

(* On définit un etudiant3 *)
let etudiant3 = {
 nom = "Math";
 prenom = "eux";
 age = 19;
 note = {maths = 24.; programmation = 11.; assiduite = 15.};
 occupation = Etude;
 ordi = {machine = Pc; ram = 4096; rom = 350000}
};;

let classe = [etudiant1]@[etudiant2]@[etudiant3];;
(* etudiant1, etudiant2 et etudiant3 sont des variables de type etudiant. *)
(* On peut donc créer une liste de ces variables qui représente une classe (de 3 élèves :-) ) *)

Voilà on peut créer des étudiants qui ont beaucoup de caractéristiques, ce que je veux vous montrer ici c'est qu'il n'y a pas de limite ! Vous pouvez créer les types de vous voulez (selon vos besoins ou souhaits).


Ce tutoriel touche à sa fin !
Niveau théorie, vous êtes fin prêt !
N'hésitez pas à revoir les chapitres que vous ne maîtrisez pas assez (ou du tout). Et surtout, postez des commentaires, questions, remarques, ou autre.
Il ne vous reste plus que la pratique (sauf que c'est encore plus long que la théorie, comme dans la plupart des langages de programmation).
Donc n'éteignez pas votre PC et direction les exercices.

Et pour les curieux, jettez un oeil aux annexes !

Choses à savoir :

- Se servir d'Ocaml
  (Interpréteur + Compilateur) avec les fichiers .ml

- Créer des variables de types classiques
  (Ocaml est un langage très typé !)

- Créer des fonctions
  (qui fonctionnent :-/ et qui répondent à un besoin :-\ )

- Créer des fonctions récursives
  (vous pouvez être sûr d'en avoir à chaque contrôle)

- Créer, modifier, manipuler, traiter, ... des listes
  (La partie la plus hardue !)

- Créer vos propres types
  (on vient de le voir ensemble ;-) !)

Je vous assure que si vous faîtes sérieusement ce tutoriel vous obtiendrez minimum 14/20 en Prog2 de Paris Descartes.
Pour avoir plus, il ne s'agit que de pratique afin de gagner en aisance et rapidité =)