Comment ça marche?
Que fait une déclaration de type ?
-
Elle crée une nouvelle structure de données
- Elle déclare des créateurs (étiquettes de types enregistrements,
constructeurs de types sommes, nouvelle exception)
- Elle crée des motifs de filtrage
Exemple des types date, saison, boîte, des
exceptions Stop et Trouvé
#type C =
| C1 | C2 | C3 of int * float * string;;
Le type C est défini.
#(1, 1.2, "allo");;
- : int * float * string = 1, 1.2, "allo"
#C3 (1, 1.2, "allo");;
- : C = C3 (1, 1.2, "allo")
À quoi sert le constructeur "C3", qu'ajoute-t-il au triplet (1, 1.2, "allo")? Il contient de l'information:
#type légumes =
| Céleri
| Betteraves of int
| Carottes of float
| Navets of float;;
Le type légumes est défini.
#1.2;;
- : float = 1.2
#Carottes 1.2;;
- : légumes = Carottes 1.2
#Navets 1.2;;
- : légumes = Navets 1.2
#2;;
- : int = 2
#Betteraves 2;;
- : légumes = Betteraves 2
Le filtrage ne calcule rien en soi
UNIX $ camllight
> Caml Light version 0.74
#match random__int 3 with
| 0 -> 1
| 1 -> 2
| 2 -> 3;;
Entrée interactive:
>match random__int 3 with
>| 0 -> 1
>| 1 -> 2
>| 2 -> 3..
Attention: ce filtrage n'est pas exhaustif.
- : int = 2
Le filtrage, les gardes et le
if ... then
... else ...
Il ne faut pas confondre :
-
le motif de filtrage qui précise la forme
attendue dans ce cas-là
- la garde d'un motif de filtrage ou la condition du if
... then ... else ... qui sont des expressions booléennes.
Une erreur classique: négliger la portée statique du typage
#type titi= Titi1 | Titi2;;
Le type titi est défini.
#let f = function t ->
match t with
| Titi1 -> 1
| Titi2 -> 2;;
f : titi -> int = <fun>
#type titi = Titi1 | Titi2 | Titi3;;
Le type titi est défini.
#f Titi1;;
Entrée interactive:
>f Titi1;;
> ^^^^^
Cette expression est de type titi,
mais est utilisée avec le type titi.
Il y a portée statique du typage: on a redéfini le type titi
mais sans redéfinir la fonction f. Titi1 est du
nouveau type titi et f prend un argument du type
titi précédent.
Le chargement et la compilation des fichiers
Comment charger en Caml le fichier monfichier.ml ?
include "monfichier";;
Exemple
UNIX $ cat monfichier.ml
let rec fact = function n ->
if n <= 0 then 1 else n*fact(n-1);;
let rec fib = function n ->
if n <= 1 then 1 else fib(n-1)+fib(n-2);;
fact 5;;
fib 10;;
print_int (fact 10);;
print_string "Ça c'est la fin de tout";
print_newline();;
UNIX $ camllight
> Caml Light version 0.74
#include "monfichier";;
fact : int -> int = <fun>
fib : int -> int = <fun>
- : int = 120
- : int = 89
3628800- : unit = ()
Ça c'est la fin de tout
- : unit = ()
- : unit = ()
#quit();;
Comment produire un exécutable à partir d'un seul fichier ?
UNIX $ camlc monfichier.ml
UNIX $ ./a.out
3628800Ça c'est la fin de tout
en le nommant
UNIX $ rm -f a.out
UNIX $ camlc -o monfichier monfichier.ml
UNIX $ ./monfichier
3628800Ça c'est la fin de tout
Les .zi et .zo
Quels fichiers existent à présent ?
UNIX $ ls
monfichier
monfichier.ml
monfichier.zi
monfichier.zo
Que sont les fichiers monfichier.zi et monfichier.zo?
-
monfichier.zo est le fichier de code objet: il contient
du code compilé pas encore exécutable, car faisant référence à des
identificateurs extérieurs;
- monfichier.zi est le fichier d'interface compilée: il
contient des informations de typage sur les objets déclarés dans le
module monfichier: type des identificateurs définis, noms de
types sommes déclarés avec leurs constructeurs, de types
enregistrements déclarés avec leur étiquette, etc.
Il sert pour la compilation des modules qui utilisent le module
monfichier (qui contiennent #open "monfichier" ou
monfichier__fib
par exemple).
Contrainte ¾® ordre de compilation
Les fichiers monfichier.zi et monfichier.zo sont
produits par camlc -c monfichier.ml qui ne produit que ces
fichiers sans produire d'exécutables, ce qui sert quand on doit
compiler plusieurs fichiers et les lier ensemble.
Édition de liens
UNIX $ camlc -o monapplication monfichier.zo
les_modules_qui_utilisent_monfichier.zo
Les .mli
Si certaines définitions servent dans un module, mais sont sans
intérêt dans les modules appelant, on peut éviter de les exporter, on
écrit alors le fichier monfichier.mli. SI on n'en a pas écrit
tout est exporté, c'est comme si monfichier.mli contenait
UNIX $ camlc -i monfichier.ml
value fact : int -> int;;
value fib : int -> int;;
(* - : int *)
(* - : int *)
(* - : unit *)
(* - : unit *)
monfichier.zi est une version compilée de ces informations.
Si on exporte fact mais pas fib par exemple, on écrit
UNIX $ cat monfichier.mli
value fact : int -> int;;
Cette interface se compile avec
UNIX $ camlc -c monfichier.mli
Lorsqu'on compile monfichier.ml, Caml vérifie la cohérence de
l'implémentation ave cl'interface compilée monfichier.zi
(identificateurs déclarés et types).
Et en interactif?
Comment compiler sous la commande interactive camllight
UNIX $ camllight
> Caml Light version 0.74
#compile "monfichier.ml";;
- : unit = ()
#load_object "monfichier.zo";;
3628800Ça c'est la fin de tout
- : unit = ()
load_object "monfichier.zo";;
charge en mémoire le code
compilé et l'exécute.
Il existe aussi la fonction load qui
permet de charger monfichier.ml en mémoire et de le considérer
comme un module de nom monfichier. Il faut alors l'ouvrir avec
#open pour accèder à son contenu.
UNIX $ camllight
> Caml Light version 0.74
#load "monfichier.ml";;
fact : int -> int = <fun>
fib : int -> int = <fun>
- : int = 120
- : int = 89
3628800- : unit = ()
Ça c'est la fin de tout
- : unit = ()
- : unit = ()
#fact;;
Entrée interactive:
>fact;;
>^^^^
L'identificateur fact n'est pas défini.
##open"monfichier";;
#fact;;
- : int -> int = <fun>
Une ligne de commande qui marche pour le TP1
camlc -custom unix.zo graphics.zo \
same_game.ml -o same -lgraph -lunix \
-ccopt -L/usr/X11R6/lib -lX11
Un petit Makefile pour Caml
ALLFILES = liste des fichiers .ml dans l'ordre
OBJS = liste des fichiers .zo correspondants
exécutable: $(OBJS)
camlc -o le nom de l'exécutable $(OBJS)
clean:
rm -f *.zo *.zi
.mli.zi:
camlc -c $<
.ml.zo:
camlc -c $<
# dépendances générales
.SUFFIXES :
.SUFFIXES : .ml .mli .zo .zi
# construire les dépendances avec camldep
depend: $(ALLFILES)
camldep *.mli *.ml > .depend
include .depend
La commande camldep permet de déterminer automatiquement les
dépendances de fichiers Caml.
Pour une version plus complète de Makefile, aller voir
http://caml.inria.fr/FAQ/Makefile_caml.tpl.
Ce document a été traduit de LATEX par
HEVEA.