Guide OCaml pour Débutants en MP2I
Guide OCaml pour Débutants en MP2I
Installation d’OCaml - Travailler en en fin de ligne avec CTRL E. Les bases de OCaml
ligne — Pour l’éditeur (open source) VSCode, voir : https://
marketplace.visualstudio.com/items?itemName= Les types de données fondamentaux
ocamllabs.ocaml-platform pour la configuration.
Installer les outils de base — On peut également installer un noyau OCaml pour Les entiers
Pour tous les systèmes d’exploitations ., il existe des distri- Jupyter-Notebooks : https://github.com/akabe/ 1 # 4 + 5;; OCaml
butions de OCaml : https://v2.ocaml.org/docs/install. ocaml-jupyter, ce qui permet de travailler dans un 2 - : int = 9
utiliser des conteneurs Docker. le typage statique en C, par exemple dans la déclaration du 3 # 2 - (3 + 5);;
— Installer un switch type (le int de int x = 42;) au moment de créer une va- 4 - : int = -6
Une fois opam installé, on peut installer sa ou ses riable. Il n’y aura pas de convesrion automatique en cas d’in- 5 # 2 - 3 + 5;;
propres distributions de OCaml. compatibilité du type d’une expression avec le type attendu 6 - : int = 4
Dans un terminal, commencez par lancer opam init par son utilisation. Pour autant, le type d’une expression n’est
pour initialiser la configuration d’opam, puis on va pas forcément précis. Il est déduit en OCaml par les opéra- La division est entière par défaut :
choisir une version de OCaml avec opam switch teurs et fonctions, entre autres, impliqués dans l’expression,
c’est ce qu’on appelle l’inférence de type, ce qui laisse parfois 1 # 11 / 3;; OCaml
create 5.0.0 (version publié le 16/12/2022).
Vous obtenez ainsi une version récente d’OCaml. un doute. Par exemple, la fonction identité sera de type « fonc- 2 - : int = 3
tion qui à une expression de type noté 'a associe un objet 3 # 11 / 3*2;;
En cas de problèmes de compatibilité, on peut égale-
de type 'a » (on parle de polymorphisme). De même, l’opé- 4 - : int = 6
ment installer le switch 4.14.1 qui sera mis à jour au
rateur de comparaison nécessite deux opérandes du même 5 # 11 / (3*2);;
moins jusqu’en 2024.
type, mais celui-ci peut être quelconque. En particulier, on n’a 6 - : int = 1
Travailler en ligne
> ledit ocaml sh Enfin, sur un processeur 64 bits, les entiers sont compris entre
Quelques sites où l’on peut coder directement en OCaml en
−262 et 262 − 1 (plage inférieure à celle du C)
Il permet d’utiliser l’interpréteur dans un terminal et ligne :
de bénéficier en outre de l’historique des commandes — https://basthon.fr ou Capytale via Moodle. 1 # max_int;; OCaml
via par les flèches haut et bas du clavier. On peut éga- — https://www.france-ioi.org/index.html 2 - : int = 4611686018427387903
lement revenir au début de ligne avec CTRL A et aller — https://try.ocamlpro.com
MP2I — 2023 – 2024 Fiche Memo Débuts avec OCaml - Gérard Rozsavolgyi LIV, Valbonne
Les déclarations 1 # let delta = OCaml Et utiliser le cas par défaut (tout autre cas), signalé par un _ :
fun (a, b,c) -> b*b - 4*a*c;;
let
2
3 val delta : int * int * int -> int = <fun> 1 # let nand a b = OCaml
A la manière d’autres langages, comme Javascript. 4
2 match (a, b) with
5 # delta(1,2,3);; 3 | (true, true) -> false
1 # let x = 3 * 4;; OCaml - : int = -8
6
4 | _ -> true;;
2 val x : int = 12
5 val nand : bool -> bool -> bool = <fun>
Notez que delta est bien décrite par OCaml comme une fonc-
Déclarations locales
6 # nand true true;;
tion : 𝑖𝑛𝑡 ∗𝑖𝑛𝑡 ∗𝑖𝑛𝑡− > 𝑖𝑛𝑡 =< 𝑓𝑢𝑛 > qui indique qu’il s’agit 7 - : bool = false
On peut définir localement une variable, avec une portée li- d’une fonction de ℤ3 dans ℤ. 8 # nand false false;;
mitée à l’expression où elle a été définie : On peut également déclarer la fonction sous la forme : 9 - : bool = true
6 val xor : bool * bool -> bool = <fun> 2 val carre' : float -> float = <fun> On peut à présent composer des fonctions, cette fois avec des
7 # xor true true;; 3 # carre' 3.;; types génériques :
8 - : bool = false 4 - : float = 6.00000049644222599
9 # xor true false;; 1 # let compose f g = fun x -> f (g x);; OCaml
10 - : bool = true 2 val compose : ('a -> 'b) -> ('c -> 'a) -> 'c
Ce qui semble une approximation raisonnable … ↪ -> 'b = <fun>
Si nous reprenons la fonction anonyme fun x -> x *. x Attention ! 6 let rec fact(n)=
carre, nous pouvons à présent calculer la dérivée approchée 7 if n=0 then 1
de cette fonction au point 𝑥 = 3 grâce aux fonctions compose Ce n’est pas une méthode très fiable pour cal-
8 else n*fact(n);;
et carre. culer des dérivées secondes car les erreurs
9 val fact : int -> int = <fun>
1 d’arrondi dans les différences finies vont se cu-
1 # let carre' = deriv (fun x -> x *. x) OCaml muler. Par exemple avec un dx = 1e-10, on
↪ 1e-10;; obtient un résultat erroné.
Définition locale de fonctions
MP2I — 2023 – 2024 Fiche Memo Débuts avec OCaml - Gérard Rozsavolgyi LIV, Valbonne
3
let delta(a,b,c) =
b*b - 4*a*c
Type unit 2 - : int = 2
Il existe des fonctions qui jouent le rôle dévolu aux procé-
4 in if delta(a,b,c) = 0 then 1
dures dans les langages impératifs et qui sont à effets de
else if delta(a,b,c) < 0 then 0
bords. Ocaml étant typé, un type est tout de même affecté à
5
Récursion terminale Une autre action à effet de bord est la modification en place 1 # x := !x + 3 ;; OCaml
d’un (array) à l’aide de l’opérateur <- : 2 - : unit = ()
3 # x;;
1 let rec succ = function OCaml 1 # let v = [|1;2;3|];; OCaml 4 - : int ref = {contents = 4}
2 |0 -> 1 2 val v : int array = [|1; 2; 3|] 5 # !x ;;
3 |n -> 1 + succ(n-1) ;; 3 # v.(2) <- 42 ;; 6 - : int = 4
4 val succ : int -> int = <fun> 4 - : unit = ()
5 5 # v ;;
6 # succ(100000);; 6 - : int array = [|1; 2; 42|]
7 - : int = 100001
8 # succ(1000000);; Remarque 1
À retenir
9 Stack overflow during evaluation (looping
recursion?). On remarque au passage qu’une réaffectation est bien
↪ On évitera ce genre d’action à effet de bord
du type unit.
partout où c’est possible.
1 (* Boucle While *) OCaml ou encore, en utilisant les opérateurs standards d’addition et 3 val ( ++ ) : int * int -> int * int -> int *
2 # let sum_w(n) = de multiplication d’OCaml qui attendent deux arguments, on ↪ int = <fun>
3 let s = ref 0 in peut fixer l’un des deux pour obtenir simplement des fonc-
4 let i = ref 0 in tions d’incrémentation ou de multiplication par deux :
Que l’on utilise ensuite comme ceci :
5 while (!(!i <= n)) do
6 begin 1 let inc = ( + ) 1;; OCaml
7 s := !s + !i; 1 # (3, 4) ++ (5, 6);; OCaml
8 incr i; 1 let double = ( * ) 2;; OCaml 2 - : int * int = (8, 10)
9 end
10 done;
11 !s;; Immutabilité en OCaml
12 val sum_w : int -> int = <fun>
En OCaml, lorsqu’une valeur est créée, elle ne peut pas Conventions de nommage en OCaml
13
être modifiée. On parle d’immutabilité. Cela contraste avec
14 # sum_w(100);; — Identificateurs (variables et fonctions) : en
d’autres langages où les valeurs (ou objets) peuvent être mo-
15 - : int = 5050 ”snake_case” en minuscules, doivent être clairs et
difiées après leur création, qu’on appelle mutabilité.
Par exemple, quand on crée une liste ou un enregistrement, explicites, parfois au détriment de la concision.
on ne peut pas changer les éléments de la liste ou les champs — Modules : Utilisent le ”CamelCase” avec majuscule ini-
Signature, curryfication et fonctions partielles de l’enregistrement en place. Si on veut une liste avec des élé- tiale comme : MyFunction, UserDetails ou Montant-
ments modifiés ou un enregistrement avec des champs diffé- Total. Les noms de modules devraient être descriptifs
1 let module_carre (x, y) = x *. x +. y *. OCaml
y;; rents, il faut créer une nouvelle liste ou un nouvel enregistre- et indiquer clairement ce que le module contient ou
ment. fait.
La signature d’une fonction est l’information sur les types des — Constantes : OCaml ne distingue pas explicitement les
arguments et de la valeur de retour. Elle est donnée en OCaml 1 let liste_ori = [1; 2; 3] OCaml constantes des autres variables, mais on peut éven-
par la syntaxe : 2 let ma_nouvelle_liste = 0 :: liste_ori
tuellement utiliser des lettres majuscules ou un préfixe
nom : type_arg1 → type_arg2 → ⋯ → type_retour 3 (* Crée une nouvelle liste [0; 1; 2; 3] *)
pour indiquer une valeur constante. Une autre pra-
La fonction précédente a pour signature module_carre 4 (* liste_ori est inchangée *)
tique courante est d’utiliser un module pour grouper
: float * float → float, et la console affiche val des constantes liées.
module_carre : float * float → float = <fun>. ou encore, pour un type enregistrement : — Types et variantes : Les noms de types utilisent généra-
Ce qu’il faut comprendre, dans la syntaxe précédente de la lement le ”snake_case”, comme les identificateurs. Les
signature d’une fonction, c’est qu’en fait la fonction nom n’at- 1 type point = { x : float; y : float } OCaml constructeurs de variantes utilisent le ”CamelCase”,
tend qu’un argument et retourne une autre fonction de signa- 2 let p = { x = 1.0; y = 2.0 };; comme les modules.
ture 3 let p_modifie = { p with x = 3.0 } — Type de champs d’enregistrement et de noms de la-
nom1 : type_arg2 -> ... -> type_retour, pour laquelle 4 (* Crée un nouveau point avec x = 3.0 et y = bels : Utilisent généralement le ”snake_case”.
le principe est le même. ↪ 2.0 *) — Signatures et functors : Suivent généralement les
mêmes règles que les modules, utilisant le ”Camel-
Il est donc tout à fait possible de définir une fonction partielle
Case”.
à partir d’une telle fonction en renseignant successivement
des arguments.
Définition d’opérateurs infixes — Opérateurs infixes personnalisés : Doivent
commencer et finir par un caractère parmi
Tester à ce sujet le code suivant : On peut également définir nos propres opérateurs infixes en ! $ % & * + - . / : < = > ? @ ^ |.
OCaml. Par exemple, définissons un opérateur pour addition- — Commentaires et documentation : Les commentaires
1 let add x y = x + y;; OCaml ner deux paires : devraient être clairs et bien écrits, suivant les conven-
2
tions grammaticales standard. Utiliser des commen-
3 let add3 = add 3;; 1 # let (++) (x1, y1) (x2, y2) = OCaml
taires spéciaux ((** ... *)) pour la documentation qui
4 add3 4;; 2 (x1 + x2, y1 + y2);;
peut être extraite avec des outils comme ocamldoc.
MP2I — 2023 – 2024 Fiche Memo Débuts avec OCaml - Gérard Rozsavolgyi LIV, Valbonne