如何使Ocaml多态变体私有化

如何使Ocaml多态变体私有化,ocaml,polymorphic-variants,Ocaml,Polymorphic Variants,我想将我的一些类型转换为使用Ocaml多态变量,用开放递归分解它们,同时仍然保留现有私有非多态类型的强制执行,以及模式匹配的详尽性检查 我的产品是一个编译器,因此类型集会被各种算法更改,目前我必须包含所有构造函数,其中不应出现“assert false”的构造函数会被删除 我应该补充一点,我过去经常使用多态变量,但后来又改用普通变量,因为类型推断不能很好地处理多态变量:错误消息很难读取,而且它们的错误性比通常的错误推断要大得多,需要对参数进行更多的类型注释才能保持理智。问题是如果没有它们,私有构

我想将我的一些类型转换为使用Ocaml多态变量,用开放递归分解它们,同时仍然保留现有私有非多态类型的强制执行,以及模式匹配的详尽性检查

我的产品是一个编译器,因此类型集会被各种算法更改,目前我必须包含所有构造函数,其中不应出现“assert false”的构造函数会被删除

我应该补充一点,我过去经常使用多态变量,但后来又改用普通变量,因为类型推断不能很好地处理多态变量:错误消息很难读取,而且它们的错误性比通常的错误推断要大得多,需要对参数进行更多的类型注释才能保持理智。问题是如果没有它们,私有构造函数的强制执行很强,但是客户端算法的强制执行很弱

我不确定将构造函数的“特殊”子集与隐私结合起来是否可行。关于它的实用性有什么建议吗

编辑:简单示例类型:

(* open *)
type 'a x' = [`A | `B of 'a]

(* closed *)
type x = private 'u x' as 'u

(* open extension *)
type 'a y' = ['a x' | `C of 'a] 

(* closed extension *)
type y = private 'u y' as 'u 

let mkA () = `A
let mkB' (a:'a x') = `B a

(* how to do this? *)
let mkB (a:x) = mkB' (a :> 'a x')
对于开放递归,构造函数必须遵循类型的开放/封闭模式。客户端只会看到已关闭的版本。这意味着,与我当前的系统中单个构造函数就足够了不同,我现在需要一个用于每个封闭类型的构造函数,用于包含构造函数的每个类型


即使我能想出如何做到这一点,这是相当困难的,如果你有6个相互依赖的类型,所有这些类型都使用开放递归,导致可能的组合呈指数级增长,但与只接受运行时检查相比,这是否是一个优势还不清楚。我花了大约2个小时来添加一个新的构造函数,因为每个模式匹配都会失败,出现一个穷尽性错误,必须修复。。即使新的构造函数在编译阶段没有用处。

私有多态变量只对模块和接口感兴趣。它们在模块中是puclic的,但由于接口,在模块外部是私有的。如果您希望在模块外访问公共代表,则必须提供以下功能:

module M : sig
  (* open *)
  type 'a x' = [`A | `B of 'a]
  (* closed *)
  type x = private 'u x' as 'u
  val f: x -> x x'
end = struct
  type 'a x' = [`A | `B of 'a]
  type x = 'u x' as 'u
  let f a = a
end
另一种方法是稍微更改您的类型,只将头构造函数设置为私有:

(* open *)
type 'a x' = [`A | `B of 'a]
(* closed *)
type x = 'u x' as 'u
(* private *)
type px = private x
let f (a: px) = (a :> x)

在@ivg或@JeffreyScofield为您提供答案之前,我想请您澄清一下:
问题在于没有它们,私人构造函数的强制执行很强,但客户端算法的强制执行很弱。
坦率地说,目前,我看不出有什么理由要使用多态变量,因为有30个类型构造函数,其中一些不能出现在输入中,比如说“phase1”,但会被它引入,而另一些作为输入出现,但会被消除。假设有20个处理阶段,那么类型系统对我没有帮助,我只是得到“运行时”诊断,对于不应该发生的情况,分支会说“assert false”。加入表示编程语言结构(表达式、类型等)的自然递归组合,我的一半代码由动态检查组成(不一定是穷举的)。