Comment ça marche?





Que fait une déclaration de type ?


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 :


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? 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.