【问题标题】:Strange module loading issue in OCamlOCaml 中奇怪的模块加载问题
【发布时间】:2013-02-15 03:58:55
【问题描述】:

我有两个文件:myUnionFind.mlmyUnionFind_test.ml。这两个文件都在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);;

我试过了

ocamlfind ocamlc -package batteries -c myUnionFind.ml。成功了,我可以看到myUnionFind.cmimyUnionFind.cmo

然后我尝试通过

编译myUnionFind_test.ml

ocamlfind ocamlc -package batteries -c myUnionFind_test.ml.

它给出了这个错误:

文件“myUnionFind_test.ml”,第 3 行,字符 10-34:错误:未绑定 值 MyUnionFind.create_union


我不知道为什么。我在模块MyUnionFind中定义了create_union,为什么找不到呢?

【问题讨论】:

  • 如果您不打算将MyUnionFind_sig 签名用于MyUnionFind 模块本身之外的任何其他内容,请将签名移动到myUnionFind.mli 并删除myUnionFind.ml 中的模块签名强制。

标签: functional-programming ocaml


【解决方案1】:

你在一个模块中定义一个模块(你的 myUnionFind.ml 是一个模块)。

所以在你的测试文件中,你必须像这样打开你的模块:

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);;

或为每个调用添加前缀,例如:

let uf2 = MyUnionFind.MyUnionFind.create_union 10;;

如果您只是在 myUnionFind.ml 中定义一个模块,并且不想像以前那样有两个模块,您可以像这样创建一个 .ml 和 .mli 文件:

 (* 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 = (* ... *)

小心,如果你有id_ary字段的引用,你必须把它放在模块签名中

【讨论】:

  • 我不明白为什么我的是模块中的模块。在我的情况下,我该如何编写它只是一个级别的模块,而不是另一个级别的模块?
  • 拥有一层模块的唯一方法是写成mliml?
  • 还有如何将id_ary字段放入签名中,而不暴露整个union_find实现?
  • 在 OCaml 中,文件已经是一个模块,所以如果你想要一个级别的模块是有一个 .ml(和一个 .mli)文件。
  • 对于 id_ary,你可以有类似“getter”的东西:val id_ary: union_find -&gt; int_array 和代码 let id_ary t = t.id_ary。所以在你的测试文件中你会做类似MyUnionFind.print_array (MyUnionFind.id_ary uf2);;
【解决方案2】:

OCaml 为每个文件免费提供一个级别的模块。所以你的myUnionFind.ml 在这个免费模块中有一个模块。为避免这种情况,请在文件的顶层声明所有内容。那么你就只有一个模块,与文件同名。

【讨论】:

  • 如果我在文件的顶层声明所有内容,那么我如何控制它的签名?我不希望所有功能都暴露出来。
  • 使用.mli文件控制暴露的界面。
猜你喜欢
  • 1970-01-01
  • 2021-05-31
  • 2012-03-21
  • 1970-01-01
  • 2015-11-22
  • 2018-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多