2

我正在尝试使用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 部分以非特权方式处理,因此我将分叉然后 setuid-ing 到子级中的非特权用户。但是,这意味着我需要通过管道将 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。我如何说服它这些类型是相同的?

4

1 回答 1

4

如果Inotify模块真的是用这个签名定义的,也就是用抽象类型密封的,那么你就无法打破它的抽象来将它重新定义为一个 int。我的意思是您的签名(module type of Foo with wd := int)很聪明并且描述了您想要的接口,但实现Foo不满足它:如果类型检查器允许这样做,那么根本就不会有类型抽象。

您应该请求ocaml-inotify维护者添加编组原语(如果需要,可能会在本地分叉它)。wd = int他或她可以将转换函数发布到和从int(以便将来的实现更改仍然可以实现这些功能),或者直接发布到和从string如果您只对编组感兴趣并希望公开较少的内部函数,而不是暴露这一事实细节。

有一种解决方案可以公开更多内部细节,即来回转换为抽象类型,即使用私有类型缩写

sig
  type t = private int
  val mk : int -> t
end

This signature exposes that the internal representation is int, and allows to cast from t to int explicitly with (foo :> int) or (foo : t :> int) (you know that this is a no-op at runtime), but does not allow the inverse cast, so you are forced to use the mk function which, I assume, will do some kind of range checking to make sure that this is a valid descriptor.

(Some people will probably suggest that, as a workaround, you break the type safety of the language by using an unsafe cast that should not be named. Do not; this is bad advice.)

于 2013-03-07T14:55:31.657 回答