OCaml中类型和模块相等的规则是什么

OCaml中类型和模块相等的规则是什么,ocaml,Ocaml,我无法理解OCaml中模块的相等性。函子应该是应用性的(这是互联网所宣称的),但这似乎有时会失败,我不太明白它背后的一般规则 这是我的示例代码: module type PT = sig end module P = struct end let () = Random.self_init () module OrigHashtbl = Hashtbl module Hashtbl = struct module Make(Hash: OrigHashtbl.HashedType)

我无法理解OCaml中模块的相等性。函子应该是应用性的(这是互联网所宣称的),但这似乎有时会失败,我不太明白它背后的一般规则

这是我的示例代码:

module type PT = sig end
module P = struct end

let () =
  Random.self_init ()

module OrigHashtbl = Hashtbl
module Hashtbl = struct
  module Make(Hash: OrigHashtbl.HashedType) = struct
    let random = Random.int 1000000

    type 'a t = { t_list: (Hash.t * 'a) list }

    let create _ =
      Format.printf "Random %d@." random;
      { t_list = [] }          

    let mem ht v =
      Format.printf "Random %d@." random;
      List.mem_assoc v ht.t_list          
  end
end

module Hash = struct
  type t = int
  let equal x1 x2 = x1 = x2
  let hash x = x
end

module Wrap(P: PT) = struct
  module H = Hashtbl.Make(Hash)
end

module Wrap1 = Wrap(P)
module Wrap2 = Wrap(P)
module H1 = Wrap1.H
module H2 = Wrap2.H

let () =
  let ht = H1.create 16 in
  Format.printf "%b@." (H2.mem ht 0)
ideone的代码:

我在这里所做的是从
Hashtbl
模块创建一些函数的虚拟实现,并将其包装在我两次“调用”的functor
wrap
中,创建可以互换使用的
H1
H2
,尽管它们是捕获不同值的
random
的不同模块:

$ ./test.byte 
Random 501586
Random 681009
false
这是意料之中的,因为正如互联网所宣称的那样,OCaml函数是适用的

但是我尝试将
散列
模块移动到
包装
中,程序停止编译

module Wrap(P: PT) = struct
  module Hash = struct
    type t = int
    let equal x1 x2 = x1 = x2
    let hash x = x
  end

  module H = Hashtbl.Make(Hash)
end
Ideone的代码:

为什么呢?如果
Wrap1
Wrap2
是同一个模块(因为functor应该是应用程序,对吧?),那么
Wrap1.Hash
Wrap2.Hash
也是一样的。比较模块的一般规则是什么

注:这是另一个问题的继续。我得到的唯一答案是“OCaml函子是生成的”,这是错误的(至少有时是错误的)

编辑

也许,我问关于模块平等的问题是错误的。我真正感兴趣的是类型平等。为什么在某些情况下
Wrap1.H.t
等于
Wrap2.H.t
,而在某些情况下-不是

回答

在与@Drup讨论之后,事情对我来说变得更清楚了。适用性是指:如果
A=B
,则
F(A)=/=F(B)
,但
F(A)。t=F(B)。t
。对于
F(A)
F(B)
中定义的模块,事情取决于这些模块的定义方式。在我的示例中,是否
Wrap1.H.t=Wrap2.H.t
取决于
H
的定义。在编译的变量中,
Wrap1.H.t=Hashtbl(Hash).t=Wrap2.H.t
。在未编译的变量中,
Wrap1.H.t=Hashtbl(Wrap1.Hash).t
Wrap2.H.t=Hashtbl(Wrap2.Hash).t
,它们是不同的。

应用函数”意味着
A=B
意味着
F(A).t=F(B).t
。这并不意味着
F(A).M=F(B).M
。这是关于类型,而不是模块

创建类型和创建模块之间的一个根本区别是创建类型没有副作用(因此可以用应用程序行为处理)。创建一个模块不是没有副作用的,因此你不能认为两个不同的新模块是相同的。 octachron在最后一个答案中给出了一个很好的例子

如果希望在仍然具有本地模块的情况下保持相等,可以使用模块别名。如果您改为这样做:

module Hash0 = struct
  type t = int
  let equal x1 x2 = x1 = x2
  let hash x = x
end
module Wrap(P: PT) = struct
  module Hash = Hash0 (* the type of this module is "= Hash0" *)
  module H = Hashtbl.Make(Hash)
end
然后程序被接受


请注意,即使在失败的版本中,
Wrap1.Hash.t=Wrap2.Hash.t
仍然有效(无论其定义如何),即使模块不相等。

我在这里试图理解的是,如果
F(A).t=F(B).t
那么为什么在某些情况下
F(A).m.t=F(B).m.t
,在某些情况下-不是。我想,我问“模块相等”是错误的,因为我在这里感兴趣的是类型相等。为了拥有
Wrap1.H.t=Wrap2.H.t
,应用性要求您应该拥有
Wrap1.Hash=Wrap2.Hash
。但是,正如我在上面所展示的,如果在函子内部声明了
散列
,则情况并非如此,即使所述函子是可应用的。好吧,我明白了
Wrap1.H.t=Wrap2.H.t
是否取决于
H
的定义。在编译的变量中,
Wrap1.H.t=Hashtbl(Hash).t=Wrap2.H.t
。在未编译的变量中,
Wrap1.H.t=Hashtbl(Wrap1.Hash).t
Wrap2.H.t=Hashtbl(Wrap2.Hash).t
,它们是不同的。我会将你的答案标记为已接受,并将讨论结果添加到问题的末尾。谢谢
module Hash0 = struct
  type t = int
  let equal x1 x2 = x1 = x2
  let hash x = x
end
module Wrap(P: PT) = struct
  module Hash = Hash0 (* the type of this module is "= Hash0" *)
  module H = Hashtbl.Make(Hash)
end