Module OCAML第一类模块签名推理

Module OCAML第一类模块签名推理,module,ocaml,type-inference,signature,first-class,Module,Ocaml,Type Inference,Signature,First Class,1) 假设有一个模块 module Int_Sig_1 = struct let x = 1 end ;; 2) 以及该模块的显式签名 module type INT_SIG = sig val x:int end ;; 3) 我根据上面的模块和模块类型创建了一个一级模块 let int_sig_1 = (module Int_Sig_1:INT_SIG) let a2 = (module Int_Sig_2);; 4) 现在,我创建了另一个模块,它没有显式签名,但具有与上面相同的推断签

1) 假设有一个模块

module Int_Sig_1 =
struct
let x = 1
end
;;
2) 以及该模块的显式签名

module type INT_SIG =
sig
val x:int
end
;;
3) 我根据上面的模块和模块类型创建了一个一级模块

let int_sig_1 = (module Int_Sig_1:INT_SIG)
let a2 = (module Int_Sig_2);;
4) 现在,我创建了另一个模块,它没有显式签名,但具有与上面相同的推断签名

module Int_Sig_2 =
struct
let x =2
end
;;
5) 正如《真实世界OCAML》一书的第10章所述,“如果可以推断,模块类型不需要是一级模块构造的一部分”,我尝试使用上述模块创建第二级一级模块,但没有明确的模块类型

let int_sig_1 = (module Int_Sig_1:INT_SIG)
let a2 = (module Int_Sig_2);;
我得到以下错误

错误:无法推断此打包模块的签名

6) 然后我尝试在5中执行与上面相同的操作,但这次我将没有模块类型的第一类模块作为列表的一个元素创建,其中列表的头是一个第一类模块,它是根据上面3中的显式签名创建的

let int_sig= [int_sig_1;(module Int_Sig_2)];;
val int_sig : (module INT_SIG) list = [<module>; <module>] ;;
设int_sig=[int_sig_1;(模块int_sig_2)];;
val int_sig:(模块int_sig)列表=[;];;
我的问题是,为什么上面的5给了我一个错误,而6没有失败?

关于(5)的问题是,通常可以推断出多种模块类型。在您的示例中,至少有两种有效的模块类型可用于打包
Int\u Sig\u 2

 module type empty = sig end
 module type with_x = sig val x:int end
换句话说,两者都是

 let a2 = (module Int_Sig_2: empty)
 let a2_bis = (module Int_Sig_2:with_x)
是有效的。因此,在这种情况下,类型检查器不会尝试推断模块类型

相反,在示例(6)中,列表的类型由其第一个元素决定,其类型为
(模块INT\u SIG\u 2)
,因此类型检查器可以使用此信息推断列表第二个元素的预期类型为
(模块INT\u SIG\u 2)
。然而,颠倒这两个元素会产生类型错误。换句话说,这很好:

 [(module struct let x = 2 end: with_x); (module struct let x = 1 end)]
然而,反之亦然

[(module struct let x=2 end); (module struct let x = 3 end:with_x)];;
Error: The signature for this packaged module couldn't be inferred. 
这是因为类型检查器具有从左到右的偏差,并且首先键入列表的第一个元素。

通常,(5)的问题是,可以推断出多个模块类型。在您的示例中,至少有两种有效的模块类型可用于打包
Int\u Sig\u 2

 module type empty = sig end
 module type with_x = sig val x:int end
换句话说,两者都是

 let a2 = (module Int_Sig_2: empty)
 let a2_bis = (module Int_Sig_2:with_x)
是有效的。因此,在这种情况下,类型检查器不会尝试推断模块类型

相反,在示例(6)中,列表的类型由其第一个元素决定,其类型为
(模块INT\u SIG\u 2)
,因此类型检查器可以使用此信息推断列表第二个元素的预期类型为
(模块INT\u SIG\u 2)
。然而,颠倒这两个元素会产生类型错误。换句话说,这很好:

 [(module struct let x = 2 end: with_x); (module struct let x = 1 end)]
然而,反之亦然

[(module struct let x=2 end); (module struct let x = 3 end:with_x)];;
Error: The signature for this packaged module couldn't be inferred. 

这是因为类型检查器有从左到右的偏差,并且首先键入列表中的第一个元素。

谢谢您的清晰回答,我可以问您一个后续问题吗?当然,不要问。谢谢您的特权。假设我有1)模块类型MOD_SIG=SIG type t val min:t1)模块类型MOD_SIG=SIG type t val min val max 2)模块MOD_UINT8=struct type t=int32 let min=int32.of int 0 let max=int32.of int 255 end;;3) 模块MOD_UINT32=struct type t=int64 let min=int64.zero let max=int64.of_int 4294967295 end;;4) 2和3的一类模设uint_8=(模MOD_UINT8:MOD_SIG);;设uint_32=(模块MOD_UINT32:MOD_SIG);;5) 我想在匹配M.t和Int32->“Int32”| Int64->“Int64”的情况下编写像let module M=(val M:MOD_SIG)这样的soe,我怎么能这样做呢?你不能,类型在运行时在OCaml中被擦除。因此,在类型上进行匹配是绝对不可能的。这里的解决方案是在模块结构中添加一个
let name=“Int[N]”
。如果您在这方面有更多问题,您可能应该提出新问题。谢谢您的清晰回答,我可以问您一个后续问题吗?当然,不要问。谢谢您的特权。假设我有1)模块类型MOD_SIG=SIG type t val min:t1)模块类型MOD_SIG=SIG type t val min val max 2)模块MOD_UINT8=struct type t=int32 let min=int32.of int 0 let max=int32.of int 255 end;;3) 模块MOD_UINT32=struct type t=int64 let min=int64.zero let max=int64.of_int 4294967295 end;;4) 2和3的一类模设uint_8=(模MOD_UINT8:MOD_SIG);;设uint_32=(模块MOD_UINT32:MOD_SIG);;5) 我想在匹配M.t和Int32->“Int32”| Int64->“Int64”的情况下编写像let module M=(val M:MOD_SIG)这样的soe,我怎么能这样做呢?你不能,类型在运行时在OCaml中被擦除。因此,在类型上进行匹配是绝对不可能的。这里的解决方案是在模块结构中添加一个
let name=“Int[N]”
。如果你在这方面有更多的问题,你可能应该提出新的问题。