ocamlmktop -custom -o top nums.cma -cclib -lnumsElle est constituée de plusieurs modules. Les deux plus importants sont Num pour toutes les opérations et Arith_status pour le contrôle des options des calculs. Le type général num est un type somme regroupant trois types de base :
Les types big_int et ratio sont abstraits.
typenum
=
Int
of
int
|
Big_int
of
big_int
|
Ratio
of
ratio
/
. Par exemple l'addition de deux num s'écrira
+/ et sera de type num -> num -> num. Il en sera de
même pour les comparaisons. Voici un premier exemple qui calcule la
factorielle :
# letrec
fact_num
n
=
if
Num
.
(<=/
)n
(Num
.
Int
0
)then
(Num
.
Int
1
)
else
Num
.
(
*/
)
n
(fact_num
(
Num
.
(-/
)n
(Num
.
Int
1
)));;val fact_num : Num.num -> Num.num = <fun>
# letr
=
fact_num
(Num
.
Int
1
0
0
);;val r : Num.num = Num.Big_int <abstr>
# letn
=
Num.string_of_num
r
in
(String.sub
n
0
5
0
)
^
"..."
;;
- : string = "93326215443944152681699238856266700490715968264381..."
# openNum
;;
# letrec
fact_num
n
=
if
n
<=/
(Int
0
)then
(Int
1
)
else
n
*/
(fact_num
(
n
-/
(Int
1
)));;
val fact_num : Num.num -> Num.num = <fun>
e = lim |
|
æ ç ç è |
1 + |
|
ö ÷ ÷ ø |
|
# let
calc_e
m
=
let
a
=
Num
.
(+/
)(Num
.
Int
1
)(
Num
.
(//
)(Num
.
Int
1
)m)
in
Num
.
(
**/
)
a
m;;
val calc_e : Num.num -> Num.num = <fun>
# letr
=
calc_e
(Num
.
Int
1
0
0
);;val r : Num.num = Ratio <abstr>
# letn
=
Num.string_of_num
r
in
(String.sub
n
0
5
0
)
^
"..."
;;
- : string = "27048138294215260932671947108075308336779383827810..."
# Arith_status.arith_status();;Normalization during computation --> OFF
(returned by get_normalize_ratio ())
(modifiable with set_normalize_ratio <your choice>)
Normalization when printing --> ON
(returned by get_normalize_ratio_when_printing ())
(modifiable with set_normalize_ratio_when_printing <your choice>)
Floating point approximation when printing rational numbers --> OFF
(returned by get_approx_printing ())
(modifiable with set_approx_printing <your choice>)
Error when a rational denominator is null --> ON
(returned by get_error_when_null_denominator ())
(modifiable with set_error_when_null_denominator <your choice>)
- : unit = ()
# Arith_status.set_approx_printingtrue;;
- : unit = ()
# Num.string_of_num(calc_e
(Num
.
Int
1
0
0
));;- : string = "0.270481382942e1"
De nombreuses erreurs peuvent survenir lors d'une demande de chargement d'un module. Non seulement le fichier doit exister avec la bonne interface dans un des chemins de recherche, mais de plus, le code-octet doit être correct et chargeable. Ces erreurs sont regroupées dans un type error utilisé comme argument de l'exception Error et de la fonction error de type error -> string qui permet de convertir une erreur en description claire.
init : unit -> unit initialise le chargement dynamique add_interfaces : string list -> string list -> unit ajoute des noms de modules et des chemins de recherche pour le chargement loadfile : string -> unit charge un fichier code-octet clear_avalaible_units : unit -> unit met à vide les noms de modules chargeables et les chemins de recherche add_avalaible_units : (string * Digest.t) list -> unit ajoute un nom de module et une empreinte pour le chargement sans avoir besoin du fichier interface allow_unsafe_modules : bool -> unit accepte de charger des fichiers contenant des déclarations external loadfile_private : string -> unit le module chargé n'est pas accessible aux prochains modules chargés L'empreinte d'une interface .cmi peut être obtenue par la commande extract_crc qui se trouve dans le catalogue des bibliothèques de la distribution.
Figure 8.10 : Fonctions du module Dynlink
letg
()
=
print_string
"Je suis la fonction 'f' par défaut\n"
;
flush
stdout
;;
letf
=
ref
g
;;
print_string
"Le module 'Mod1' modifie la valeur de 'F.f'\n"
;
flush
stdout
;;
letg
()
=
print_string
"Je suis la fonction 'f' du module 'Mod1'\n"
;
flush
stdout
;;
F.f
:=
g
;;
print_string
"Le module 'Mod2' modifie la valeur de 'F.f'\n"
;
flush
stdout
;;
letg
()
=
print_string
"Je suis la fonction 'f' du module 'Mod2'\n"
;
flush
stdout
;;
F.f
:=
g
;;
Le programme principal doit, outre initialiser le chargement dynamique, déclarer par un appel à Dynlink.add_interfaces les interface utilisées.
letmain
()
=
try
Dynlink.init
()
;
Dynlink.add_interfaces
[
"Pervasives"
;
"F"
;
"Mod1"
;
"Mod2"
]
[
Sys.getcwd()
;
"/usr/local/lib/ocaml/"
]
;
!
(F.f)()
;
Dynlink.loadfile
"mod1.cmo"
;
!
(F.f)()
;
Dynlink.loadfile
"mod2.cmo"
;
!
(F.f)()
with
Dynlink
.
Errore
->
print_endline
(Dynlink.error_message
e)
;
exit
1
;;
main()
;;
$ ocamlc -c f.ml $ ocamlc -o main dynlink.cma f.cmo main.ml $ ocamlc -c f.cmo mod1.ml $ ocamlc -c f.cmo mod2.mlSi l'on exécute le programme main, on obtient :
$ main Je suis la fonction 'f' par défaut Le module 'Mod1' modifie la valeur de 'F.f' Je suis la fonction 'f' du module 'Mod1' Le module 'Mod2' modifie la valeur de 'F.f' Je suis la fonction 'f' du module 'Mod2'Au chargement dynamique d'un module, son code est exécuté. C'est ce que manifeste, dans notre exemple, les affichages commençant par Le module .... Les éventuels effets de bord qu'il contient sont donc répercutés au niveau du programme qui a effectué ce chargement. C'est pourquoi, les différents appels à F.f appellent des fonctions différentes.