ocamlmktop -custom -o top nums.cma -cclib -lnumsThe library contains many modules. The two most important ones are Num for all the operations and Arith_status for controlling calculation options. The general type num is a variant type gathering three basic types:
The types big_int and ratio are abstract.
typenum
=
Int
of
int
|
Big_int
of
big_int
|
Ratio
of
ratio
/
. For example the addition of two num variables is written
+/ and will be of type num -> num -> num. It will be the
same for comparisons. Here is the first example that calculates the
factorial:
# 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"
Many errors can occur during a request to load a module. Not only must the file exist with the right interface in one of the paths, but the bytecode must also be correct and loadable. These errors are gathered in the type error used as an argument to the Error exception and to the error function of type error -> string that allows the conversion of an error into a clear description.
init : unit -> unit initialize dynamic loading add_interfaces : string list -> string list -> unit add the names of modules and paths for loading loadfile : string -> unit load a bytecode file clear_avalaible_units : unit -> unit empty the names of loadable modules and paths add_avalaible_units : (string * Digest.t) list -> unit add the name of a module and a checksum for loading without needing the interface file allow_unsafe_modules : bool -> unit allow the loading of files containing external declarations loadfile_private : string -> unit the loaded module is not accessible to modules loaded later The checksum of an interface .cmi can be obtained from the extract_crc command found in the catalog of libraries in the distribution.
Figure 8.10: Functions of the Dynlink module.
letg
()
=
print_string
"I am the 'f' function by default\n"
;
flush
stdout
;;
letf
=
ref
g
;;
print_string
"The 'Mod1' module modifies the value of 'F.f'\n"
;
flush
stdout
;;
letg
()
=
print_string
"I am the 'f' function of module 'Mod1'\n"
;
flush
stdout
;;
F.f
:=
g
;;
print_string
"The 'Mod2' module modifies the value of 'F.f'\n"
;
flush
stdout
;;
letg
()
=
print_string
"I am the 'f' function of module 'Mod2'\n"
;
flush
stdout
;;
F.f
:=
g
;;
The main program must, in addition to initializing the dynamic loading, declare by a call to Dynlink.add_interfaces the interface used.
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.mlIf we execute program main, we obtain:
$ main I am the 'f' function by default The 'Mod1' module modifies the value of 'F.f' I am the 'f' function of module 'Mod1' The 'Mod2' module modifies the value of 'F.f' I am the 'f' function of module 'Mod2'Upon the dynamic loading of a module, its code is executed. This is demonstrated in our example, with the outputs beginning with The 'Mod.... The possible side effects that it contains are therefore reflected at the level of the program that caused the code to be loaded. This is why the different calls to F.f call different functions.