我正在尝试使用ocaml-inotify包。该问题的相关部分可以定义如下
module Inotify : sig
type wd
val int_of_wd : wd -> int
end = struct
type wd = int
let int_of_wd wd = wd
end
这项工作是在一个setuid脚本中进行的,我希望inotify部分处理得没有特权,所以我要分配,然后安排到孩子的非特权用户。但是,这意味着我需要通过管道将wd实体传递回父级,因此需要序列化和反序列化它们,需要int_to_wd
函数。
我尝试按如下方式扩展模块:
module Rich_Inotify : sig
include module type of Inotify with type wd := int
val wd_of_int : int -> wd
end = struct
include Inotify
let wd_of_int (wd:int) : wd = wd
end
module Inotify = Rich_Inotify
但是,编译器抱怨wd
是int
而不是wd
。我如何说服这些类型相同?
答案 0 :(得分:4)
如果Inotify
模块确实是用这个签名定义的,那么用抽象类型密封,你就无法打破它的抽象,把它重新定义为int。我的意思是你的签名(module type of Foo with wd := int)
很聪明,并描述了你想要的界面,但实现Foo
不满足它:如果类型检查器允许,那么就会有根本没有类型抽象。
您应该请求ocaml-inotify
维护者添加编组基元(如果需要,可以在本地分叉)。他或她可以向wd = int
发布转换函数(以便将来的实现更改仍然可以实现这些函数),或者直接来往于int
,而不是公开string
的事实。如果你只对编组感兴趣并希望公开更少的内部细节。
有一个解决方案可以公开更多内部细节,即来回转换为抽象类型,即使用private type abbreviations:
sig
type t = private int
val mk : int -> t
end
此签名公开内部表示为int
,并允许使用t
或int
明确地从(foo :> int)
投射到(foo : t :> int)
(您知道这是运行时的无操作),但是不允许反向转换,所以你不得不使用mk
函数,我认为它将进行某种范围检查以确保这是一个有效的描述符。
(有些人可能会建议,作为一种解决方法,您可以通过使用不应该命名的不安全的强制转换来破坏语言的类型安全性。不要;这是不好的建议。)