Avant d'aller plus loin, et de découvrir une des fonctionalité les plus importantes d'OCaml, il est utile de faire une pause et de résumer les types que l'on connait.
Nous avons vu les types "de base":
bool
pour les booléens: "vrai" ou "faux".int
pour les entiers: 420
, 2
, ...float
pour les nombres à virgule: 4.14
, 2.0
, 3.33334
, ...char
pour les caractères: a
, \n
, #
string
pour les chaînes de caractères: "salut tout le monde"
, ...Mais aussi des types pour combiner des types en des types nouveaux:
int
et du type float
, on
a le type fonction int -> float
. float
, on peut créer le
type des listes de nombres à virgule : float list
.Est-ce que ça suffit ? Non ! Pourquoi ?
OCaml permet de créer des types personnalisés pour représenter ce que l'on veut ! Par exemple on pourra créer des types pour :
Mais avant de créer ces types, nous allons nous concentrer sur les types que l'on connait déjà, et voir comment ils ont été défini ! Et comment nous aurions pu les définir nous-même !
OCaml nous permet de jeter un oeil à la définition d'un type:
#show bool
et le résultat ne se fait pas attendre!
type bool = false | true
Mais qu'est-ce que cela peut bien vouloir dire ?
type
" ?bool
" ?=
" ?false
" ?|
" ?true
" ?type
nous indique que l'on va déclarer un type, et non autre chose (une
valeur, un module, une pâte à tartiner, ...)bool
est le nom du type,false
et true
sont les deux valeurs que peuvent prendre le type,|
sert à séparer les différentes valeurs possibles.On appelle ça un type énuméré : un type dont la définition énumère les différentes valeurs possibles.
Essayons tout d'abord de recréer le type booléen :
type mon_bool = true | false
Est-ce que ça marche ? Oui !
Alors, mettons-le en français :
type mon_bool = vrai | faux
Est-ce que ça marche ? Non !
Pour éviter de "confondre" les "valeurs de base" des valeurs normales, on force à utiliser des majuscules pour les nouvelles valeurs de base.
On appelle les "valeurs de base" définie lors de la création d'un type des "constructeurs". Rappelez-vous ce terme ! Ils sont toujours en majuscule.
type mon_bool = Vrai | Faux
Mais plutôt que de reprendre un type existant, ce qui n'est pas très utile, créens-on un nouveau !
type maille = Endroit | Envers
Note : Il n'y a que deux possibilités, comme pour les booléens ! On aurait pu utiliser des booléens pour représenter ces valeurs, mais cela ne pourrait que nous mélanger les aiguilles, et générer des bugs !
Nous pouvons maintenant filtrer et utiliser ces valeurs:
let esthetique maille =
match maille with
| Endroit -> 1.3
| Envers -> 1.2
let retournement maille =
match maille with
| Endroit -> Envers
| Envers -> Endroit
Augmentons un peu le type...
type maille =
| Endroit
| Envers
| Glisse (** Passe une maille d'un côté à l'autre sans la tricoter *)
| Jete (** "Jette" une maille *)
| Augmente (** Crée deux mailles à partir d'une seule *)
Horreur ! Le filtrage n'est plus exhaustif ! Corrigeons cela tout de suite !
Le fait que OCaml soit capable d'emettre un warning est un très bon point pour la maintenance des projets.
Dans certains cas, on peut se permettre d'avoir un "cas joker":
let connu_de_paul_elliot maille =
match maille with
| Endroit -> true
| Envers -> true
| _ -> false
Même si on rajoute un nouveau genre de point, Paul-Elliot ne le connaitra pas pour autant.
Les constructeurs permettent de créer des valeurs incompatibles. Cependant:
On peut ajouter des données à un constructeur.
type temperature_dimensionnee =
| Celsius of float
| Farenheit of float
let temp_corporelle = Celsius 37.
let en_farenheit t = match t with
| Farenheit f -> f
| Celsius c -> (c *. 9.) /. 5. +. 32.
type json =
| Null
| Bool of bool
| Int of int
| Float of float
| String of string
| Array of json list
| Object of (string * json) list;;
On peut combiner des valeurs en une seule en utilisant des enregistrements. La syntaxe est la suivante :
type ethique = Loyal | E_Neutre | Chaotique
type moral = Bon | M_Neutre | Mauvais
type personnage_dd = {
nom : string
ethique : ethique;
moral : moral;
}
let p = { nom = "Monsieur L" ; ethique = Loyal ; moral = Bon}
let nom_de p = p.nom
let est_pire p = match p with
| {nom = _ ; ethique = Chaotique ; moral = Mauvais} -> true
| _ -> false
option
permet de définir une valeur qui peut être présente, ou absente :type 'a option =
| None (** La valeur est absente *)
| Some of 'a (** La valeur est présente *)
list
permet de définir une liste de valeurs :type 'a list =
| [] (** La liste est vide *)
| ( :: ) of 'a * 'a ilst (** Un élément en tête, et le reste de la liste *)
either
permet de définir l'union de deux types :type ('a, 'b) either =
| Left of 'a (** Un élément de type 'a *)
| Right of 'b (** Un élément de type 'b *)