【发布时间】:2015-03-18 06:18:19
【问题描述】:
我有一组复杂的限制(主要是教学),导致我想做这样的事情:
type alpha = ... ENV.env ...
and module type ENV = sig
type env
val foo : ...alpha...
end
但这不是合法的 OCaml。一方面,您不能将 module type ENV = 作为递归类型定义的一部分。 (我认为甚至没有任何版本的递归声明仅限于模块类型声明。)对于两个,你不能让ENV.env 调用模块的组件type;你只能写M.env 其中M 是一个实现的模块结构。但是,如果像上面这样的事情是合法的,它就会捕捉到我的目标。
这是一个简化的测试用例,展示了我的一些限制。
(* M1 is really the contents of an .mli file, not a module *)
module M1 = struct
type env (* I want env to be opaque or abstract at this point ... *)
type alpha = A of int | B of env * int
type beta = C of int | D of alpha
module type ENV = sig
type env (* ...but to be unified with this env *)
val foo : unit -> beta -> unit
val empty : env
end
end
(* M2 needs to be in another_file.ml *)
module M2 = struct
(* here we provide an implementation of M1.ENV *)
module E1 : M1.ENV = struct
type env = char
let foo () _ = ()
let empty = 'X'
end
(* then I'd want this to typecheck, but it doesn't *)
let _ = M1.B(E1.empty, 0)
end
在M1中,ENV声明前的部分需要引用env类型,但随后ENV的声明本身需要引用@其他部分发生的一些事情987654331@。所以不清楚哪个应该先出现。如果ENV 不需要引用beta,而后者又引用alpha,我可以将ENV 放在文件的开头和include ENV(正如我上面所说,这真的是一个.mli 文件),以便访问 env 类型以声明 alpha。我不确定这是否真的会导致alpha 中的env 与M1.ENV 中的env 相同(在OCaml include 中,模块类型据说只是一个文本副本其内容);但无论如何,由于相互依赖,我不能在这里做。所以我必须在M1的开头预先声明type env。我们无法在 M1 中指定 env 的实现,这对我的需求至关重要。
我上面给M1 的声明被OCaml 接受,但是env 这两种类型并没有统一。这并不奇怪,但我的任务是找到一些能够统一它们的扭曲。当我们稍后提供ENV 的实现时,如上面的M2,我们希望能够使用它来提供M1.alpha 的实例。但目前我们不是:M1.B(E1.empty, 0) 不会进行类型检查。
现在有一个解决方案。我可以让M1.alpha 使用类型变量'env 而不是抽象类型env。但是M1.alpha 需要在'env 上进行参数化,然后M1.beta 也需要进行参数化,并且由于我的类型相互依赖,整个项目中的几乎每个类型都需要在'env 类型,一个具体的实例,直到我们到达 module M2,我们才能提供它,在构建链的更下方。这在教学上是不可取的,因为它使所有类型都更难理解,即使在环境没有直接相关性的情况下也是如此。
所以我一直在试图弄清楚是否有一些技巧可以用函子或一流的模块执行,使我能够获得我在module M1 中寻找的那种相互依赖关系,并提供一个在后面的文件中实现env 类型,这里用module M2 表示。我还没有弄清楚这样的事情。
【问题讨论】: