使用海市rage楼,我有一个很大的函子烂摊子。为了稍微清理一下,我对我需要在代码中传递的所有类型和值进行了参数化处理,制作了一个丑陋的Context
模块。由于显然仅传递我需要的值将允许类型“转义其范围”以引用编译器,因此我最终只是将该模块作为函数的参数传递
fun x (module Ctx : Context) ... =
使用起来有点烦人,但它可以工作。 所以基本上:
let module Context = MkContext(S)(C)(ContextConfig) in
S.listen_tcpv4 stackv4 ~port:8442 (Context.handleConnection console);
从Context.handleConnection内部,我需要调用一个以Context为参数的函数。我猜想的一种方法是将Context传递给handleConnection,就像这样:
S.listen_tcpv4 stackv4 ~port:8442 (Context.handleConnection console (module Context));
然后将它作为一个this从handleConnection传递给需要该函数的函数,但我想必须有更好的方法吗?
编辑:甚至无法做到这一点,我需要对模块类型进行递归,这似乎并不简单。
答案 0 :(得分:1)
我不确定这是否是个好主意,但是可以通过递归模块定义递归模块类型:
module rec R: sig
module type S = sig
val f: (module R.S) -> int -> int
end
end = R
我们在这里使用的技巧是在递归模块扩展过程中添加类型级别的组件,以避免重复。没有这个技巧,可能最好开始使用占位符self
类型定义内部模块类型
module type I = sig
type self
val f: self -> int -> int
end
然后,我们可以在递归定义中删除占位符类型:
module rec R : sig
module type S = I with type self := (module R.S)
end = struct
module type S = I with type self := (module R.S)
end
最后,我们可以将递归模块类型用于
module X = struct
let f (module Self: R.S) n =
if n = 0 then 1 else n * Self.f (module Self) (n-1)
end
let six = X.f (module X) 3