OCaml中类型和模块相等的规则是什么
我无法理解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)
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
模块创建一些函数的虚拟实现,并将其包装在我两次“调用”的functorwrap
中,创建可以互换使用的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