无法在递归函数中推断出此打包模块的签名
The signature for this packaged module couldn't be inferred in recursive function
我仍在尝试弄清楚在使用 Mirage 时如何拆分代码,它是第一个 class 模块的无数个。
我把我需要的一切都放在一个丑陋的大 Context
模块中,以避免必须将十个模块传递给我的所有功能,一个就够痛苦的了。
我有一个通过 tcp 接收命令的功能:
let recvCmds (type a) (module Ctx : Context with type chan = a) nodeid chan = ...
经过数小时的反复试验,我发现我需要添加 (type a)
和 "explicit" type chan = a
才能使其正常工作。看起来很丑,但它可以编译。
但是如果我想让那个函数递归:
let rec recvCmds (type a) (module Ctx : Context with type chan = a) nodeid chan =
Ctx.readMsg chan >>= fun res ->
... more stuff ...
|> OtherModule.getStorageForId (module Ctx)
... more stuff ...
recvCmds (module Ctx) nodeid chan
我通过了两次模块,第一次没问题但是
我在递归行上收到错误:
The signature for this packaged module couldn't be inferred.
如果我尝试指定签名,我会得到
This expression has type a but an expression was expected of type 'a
The type constructor a would escape its scope
而且我似乎无法使用整个 (type chan = a)
东西。
如果有人可以解释发生了什么,最好是解决它的方法,那就太好了。
我当然可以只用一会儿,但我宁愿最终理解这些该死的模块。谢谢!
实用的答案是递归函数应该用 let rec f: type a. .... = fun ...
普遍量化它们的局部抽象类型。
更准确地说,您的示例可以简化为
module type T = sig type t end
let rec f (type a) (m: (module T with type t = a)) = f m
产生与您相同的错误:
Error: This expression has type (module T with type t = a)
but an expression was expected of type 'a
The type constructor a would escape its scope
这个错误可以通过显式的 forall 量化来修复:这可以通过
速记符号(用于通用量化的局部抽象类型):
let rec f: type a. (module T with type t = a) -> 'never = fun m -> f m
此行为背后的原因是局部抽象类型不应转义
引入它们的函数的范围。例如,这段代码
let ext_store = ref None
let store x = ext_store := Some x
let f (type a) (x:a) = store x
应该明显失败,因为它试图存储类型 a
的值,这是 f
主体之外的无意义类型。
因此,具有局部抽象类型的值只能由多态函数使用。比如这个例子
let id x = x
let f (x:a) : a = id x
很好,因为 id x
适用于任何 x
.
像
这样的函数的问题
let rec f (type a) (m: (module T with type t = a)) = f m
那么 f
的类型还没有在它的体内泛化,因为 ML 中的类型泛化发生在 let
定义处。因此,解决方法是明确告诉编译器 f
在其参数中是多态的:
let rec f: 'a. (module T with type t = 'a) -> 'never =
fun (type a) (m:(module T with type t = a)) -> f m
这里,'a. ...
是一个通用量化,应该读作 forall 'a. ...
。
第一行告诉编译器函数 f
在它的第一个参数中是多态的,而第二行显式地引入局部抽象类型 a
来改进打包模块类型。拆分这两个声明非常冗长,因此 shorthand 符号结合了两者:
let rec f: type a. (module T with type t = a) -> 'never = fun m -> f m
我仍在尝试弄清楚在使用 Mirage 时如何拆分代码,它是第一个 class 模块的无数个。
我把我需要的一切都放在一个丑陋的大 Context
模块中,以避免必须将十个模块传递给我的所有功能,一个就够痛苦的了。
我有一个通过 tcp 接收命令的功能:
let recvCmds (type a) (module Ctx : Context with type chan = a) nodeid chan = ...
经过数小时的反复试验,我发现我需要添加 (type a)
和 "explicit" type chan = a
才能使其正常工作。看起来很丑,但它可以编译。
但是如果我想让那个函数递归:
let rec recvCmds (type a) (module Ctx : Context with type chan = a) nodeid chan =
Ctx.readMsg chan >>= fun res ->
... more stuff ...
|> OtherModule.getStorageForId (module Ctx)
... more stuff ...
recvCmds (module Ctx) nodeid chan
我通过了两次模块,第一次没问题但是 我在递归行上收到错误:
The signature for this packaged module couldn't be inferred.
如果我尝试指定签名,我会得到
This expression has type a but an expression was expected of type 'a
The type constructor a would escape its scope
而且我似乎无法使用整个 (type chan = a)
东西。
如果有人可以解释发生了什么,最好是解决它的方法,那就太好了。
我当然可以只用一会儿,但我宁愿最终理解这些该死的模块。谢谢!
实用的答案是递归函数应该用 let rec f: type a. .... = fun ...
普遍量化它们的局部抽象类型。
更准确地说,您的示例可以简化为
module type T = sig type t end
let rec f (type a) (m: (module T with type t = a)) = f m
产生与您相同的错误:
Error: This expression has type (module T with type t = a) but an expression was expected of type 'a The type constructor a would escape its scope
这个错误可以通过显式的 forall 量化来修复:这可以通过 速记符号(用于通用量化的局部抽象类型):
let rec f: type a. (module T with type t = a) -> 'never = fun m -> f m
此行为背后的原因是局部抽象类型不应转义 引入它们的函数的范围。例如,这段代码
let ext_store = ref None
let store x = ext_store := Some x
let f (type a) (x:a) = store x
应该明显失败,因为它试图存储类型 a
的值,这是 f
主体之外的无意义类型。
因此,具有局部抽象类型的值只能由多态函数使用。比如这个例子
let id x = x
let f (x:a) : a = id x
很好,因为 id x
适用于任何 x
.
像
这样的函数的问题 let rec f (type a) (m: (module T with type t = a)) = f m
那么 f
的类型还没有在它的体内泛化,因为 ML 中的类型泛化发生在 let
定义处。因此,解决方法是明确告诉编译器 f
在其参数中是多态的:
let rec f: 'a. (module T with type t = 'a) -> 'never =
fun (type a) (m:(module T with type t = a)) -> f m
这里,'a. ...
是一个通用量化,应该读作 forall 'a. ...
。
第一行告诉编译器函数 f
在它的第一个参数中是多态的,而第二行显式地引入局部抽象类型 a
来改进打包模块类型。拆分这两个声明非常冗长,因此 shorthand 符号结合了两者:
let rec f: type a. (module T with type t = a) -> 'never = fun m -> f m