gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 09:14:00 25 4
gpt4 key购买 nike

我无法理解 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代码: https://ideone.com/5C8Muk

我在这里所做的是从 Hashtbl 创建一些函数的虚拟实现。模块并将其包装在仿函数中 Wrap我“调用”两次,创建 H1H2尽管它们是捕获 random 不同值的不同模块,但它们可以互换使用:
$ ./test.byte 
Random 501586
Random 681009
false

这是意料之中的,因为正如 Internet 所声称的那样,OCaml 仿函数是适用的。

但后来我尝试移动 Hash模块内 Wrap并且程序停止编译。
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 代码: https://ideone.com/Gjxc32
$ ocamlbuild test.byte
+ /home/XXX/.opam/4.04.0/bin/ocamlc.opt -c -o test.cmo test.ml
File "test.ml", line 41, characters 35-37:
Error: This expression has type 'a H1.t = 'a Hashtbl.Make(Wrap1.Hash).t
but an expression was expected of type
'b H2.t = 'b Hashtbl.Make(Wrap2.Hash).t

这是为什么?我希望如果 Wrap1Wrap2是同一个模块(因为仿函数应该是适用的,对吧?)然后 Wrap1.HashWrap2.Hash也是一样的。比较模块背后的一般规则是什么?

注意:这是另一个问题 How to convince ocaml that two functor instantiations are equal 的延续.我得到的唯一答案是“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).tWrap2.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成立(不管它的定义),即使模块不相等。

关于ocaml - OCaml中类型和模块相等的规则是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48895723/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com