问题
I have two files: myUnionFind.ml and myUnionFind_test.ml. Both files are in the same directory.
myUnionFind.ml
open Batteries
module type MyUnionFindSig =
sig
type union_find
val print_array : 'a array -> unit
val create_union : int -> union_find
val union_weighted : union_find -> int -> int -> unit
val is_connected_weighted : union_find -> int -> int -> bool
end;;
module MyUnionFind : MyUnionFindSig =
struct
let print_array ary = print_endline (BatPervasives.dump ary);;
type union_find = {id_ary : int array; sz_ary : int array};;
let create_union n = {id_ary = Array.init n (fun i -> i);
sz_ary = Array.make n 1};;
(* weighted quick union find *)
let find_root ary i =
let rec find j =
if ary.(j) = j then j
else find ary.(j)
in
find i;;
let union_weighted {id_ary;sz_ary} p q =
let root_p = find_root id_ary p in
let root_q = find_root id_ary q in
if sz_ary.(root_p) < sz_ary.(root_q) then begin
id_ary.(root_p) <- id_ary.(root_q);
sz_ary.(root_q) <- sz_ary.(root_q) + sz_ary.(root_p)
end
else begin
id_ary.(root_q) <- id_ary.(root_p);
sz_ary.(root_p) <- sz_ary.(root_p) + sz_ary.(root_q)
end;;
let is_connected_weighted {id_ary;_} p q = (find_root id_ary p) = (find_root id_ary q);;
end
myUnionFind_test.ml
open Batteries
let uf2 = MyUnionFind.create_union 10;;
MyUnionFind.union_weighted uf2 0 3;;
MyUnionFind.union_weighted uf2 1 4;;
MyUnionFind.union_weighted uf2 4 3;;
MyUnionFind.union_weighted uf2 2 8;;
MyUnionFind.print_array uf2.MyUnionFind.id_ary;;
BatPervasives.print_bool (MyUnionFind.is_connected_weighted uf2 0 3);;
I tried
ocamlfind ocamlc -package batteries -c myUnionFind.ml. It worked, I can see myUnionFind.cmi and myUnionFind.cmo.
Then I tried to compile myUnionFind_test.ml via
ocamlfind ocamlc -package batteries -c myUnionFind_test.ml.
It gives this error:
File "myUnionFind_test.ml", line 3, characters 10-34: Error: Unbound value MyUnionFind.create_union
I can't figure out why. I have defined create_union in module MyUnionFind, but why it can't be found?
回答1:
You define a module in a module (your myUnionFind.ml is a module).
So in your test file, you have to open your module like this:
open Batteries
open MyUnionFind (* Here !*)
let uf2 = MyUnionFind.create_union 10;;
MyUnionFind.union_weighted uf2 0 3;;
MyUnionFind.union_weighted uf2 1 4;;
MyUnionFind.union_weighted uf2 4 3;;
MyUnionFind.union_weighted uf2 2 8;;
MyUnionFind.print_array uf2.MyUnionFind.id_ary;;
BatPervasives.print_bool (MyUnionFind.is_connected_weighted uf2 0 3);;
or prefix each call like:
let uf2 = MyUnionFind.MyUnionFind.create_union 10;;
If you just define a module in myUnionFind.ml and you don't want to have two modules like previously, you can just create a .ml and .mli file like this:
(* myUnionFind.mli *)
type union_find = {id_ary : int array; sz_ary : int array}
val print_array : 'a array -> unit
val create_union : int -> union_find
val union_weighted : union_find -> int -> int -> unit
val is_connected_weighted : union_find -> int -> int -> bool
(* myUnionFind.ml *)
type union_find = {id_ary : int array; sz_ary : int array};;
let print_array ary = (* ... *)
let create_union n = (* ... *)
let union_weighted r p q = (* ... *)
let find_root ary i = (* ... *)
Be careful, if you have a reference to id_ary field, you have to put it in the module signature
回答2:
OCaml gives you one level of module for free with each file. So your myUnionFind.ml has a module within this free module. To avoid this, declare everything at the top level of the file. Then you have just one module, with the same name as the file.
来源:https://stackoverflow.com/questions/14876228/strange-module-loading-issue-in-ocaml