OCaml 使用定义在外部仿函数的签名来限制对生成模块的可见性
OCaml use signature defined outside functor to limit visibility into produced module
我正在尝试编写一个仿函数,它接受一对有序的事物并产生另一个有序的事物(按字典顺序定义排序)。
但是,我希望生成的 "ordered type" 是抽象的,而不是 OCaml 元组。
使用 inline/anonymous 签名很容易做到这一点。
(* orderedPairSetInlineSig.ml *)
module type ORDERED_TYPE = sig
type t
val compare : t -> t -> int
end
module MakeOrderedPairSet (X : ORDERED_TYPE) :
sig
type t
val get_fst : t -> X.t
val get_snd : t -> X.t
val make : X.t -> X.t -> t
val compare : t -> t -> int
end = struct
type t = X.t * X.t
let combine_comparisons fst snd =
if fst = 0 then snd else fst
let compare (x, y) (a, b) =
let cmp = X.compare x a in
let cmp' = X.compare y b in
combine_comparisons cmp cmp'
let get_fst ((x, y) : t) = x
let get_snd ((x, y) : t) = y
let make x y = (x, y)
end
我想给我的匿名签名起一个像 ORDERED_PAIR_SET_TYPE
这样的名字,然后把它移到 MakeOrderedPairSet
的定义之外,像这样(警告:语法上无效):
(* orderedPairSet.ml *)
module type ORDERED_TYPE = sig
type t
val compare : t -> t -> int
end
module type ORDERED_PAIR_SET_TYPE = sig
type t
type el
val get_fst : t -> el
val get_snd : t -> el
val make : el -> el -> t
val compare : t -> t -> int
end
module MakeOrderedPairSet (X : ORDERED_TYPE) :
(ORDERED_PAIR_SET_TYPE with type el = X.t) = struct
type t = X.t * X.t
let combine_comparisons fst snd =
if fst = 0 then snd else fst
let compare (x, y) (a, b) =
let cmp = X.compare x a in
let cmp' = X.compare y b in
combine_comparisons cmp cmp'
let get_fst ((x, y) : t) = x
let get_snd ((x, y) : t) = y
let make x y = (x, y)
end
其中 el
是签名中的抽象类型,我试图绑定到 MakeOrderedPairSet
正文中的 X.t
。
但是,我不知道如何将所有内容组合在一起。
(ORDERED_PAIR_SET_TYPE with type el = X.t)
是我能想到的最明显的表达方式 "give me a signature that's just like this one, but with an abstract type replaced with a concrete one (or differently-abstract in this case)"。但是,在这种情况下它在语法上是无效的(因为有括号)。去掉括号也不会导致有效的 "module-language-level expression";我保留它是因为我认为它使我的意图更加明显。
那么...您如何使用命名签名来限制对[仿函数产生的模块]/[参数化模块]的可见性?
如果你不想将el
添加到模块的导出中,那么有两种方法:
使用替代约束:
ORDERED_PAIR_SET_TYPE with type el := X.t
这将从签名中删除 el
的规范。
使用参数化签名。不幸的是,这不能直接在 OCaml 中表达,但需要围绕签名的定义进行一些额外的仿函数操作:
module SET_TYPE (X : ORDERED_TYPE) =
struct
module type S =
sig
type t
val get_fst : t -> X.el
val get_snd : t -> X.el
val make : X.el -> X.el -> t
val compare : t -> t -> int
end
end
有了它你可以写:
module MakeOrderedPairSet (X : ORDERED_TYPE) : SET_TYPE(X).S = ...
我正在尝试编写一个仿函数,它接受一对有序的事物并产生另一个有序的事物(按字典顺序定义排序)。
但是,我希望生成的 "ordered type" 是抽象的,而不是 OCaml 元组。
使用 inline/anonymous 签名很容易做到这一点。
(* orderedPairSetInlineSig.ml *)
module type ORDERED_TYPE = sig
type t
val compare : t -> t -> int
end
module MakeOrderedPairSet (X : ORDERED_TYPE) :
sig
type t
val get_fst : t -> X.t
val get_snd : t -> X.t
val make : X.t -> X.t -> t
val compare : t -> t -> int
end = struct
type t = X.t * X.t
let combine_comparisons fst snd =
if fst = 0 then snd else fst
let compare (x, y) (a, b) =
let cmp = X.compare x a in
let cmp' = X.compare y b in
combine_comparisons cmp cmp'
let get_fst ((x, y) : t) = x
let get_snd ((x, y) : t) = y
let make x y = (x, y)
end
我想给我的匿名签名起一个像 ORDERED_PAIR_SET_TYPE
这样的名字,然后把它移到 MakeOrderedPairSet
的定义之外,像这样(警告:语法上无效):
(* orderedPairSet.ml *)
module type ORDERED_TYPE = sig
type t
val compare : t -> t -> int
end
module type ORDERED_PAIR_SET_TYPE = sig
type t
type el
val get_fst : t -> el
val get_snd : t -> el
val make : el -> el -> t
val compare : t -> t -> int
end
module MakeOrderedPairSet (X : ORDERED_TYPE) :
(ORDERED_PAIR_SET_TYPE with type el = X.t) = struct
type t = X.t * X.t
let combine_comparisons fst snd =
if fst = 0 then snd else fst
let compare (x, y) (a, b) =
let cmp = X.compare x a in
let cmp' = X.compare y b in
combine_comparisons cmp cmp'
let get_fst ((x, y) : t) = x
let get_snd ((x, y) : t) = y
let make x y = (x, y)
end
其中 el
是签名中的抽象类型,我试图绑定到 MakeOrderedPairSet
正文中的 X.t
。
但是,我不知道如何将所有内容组合在一起。
(ORDERED_PAIR_SET_TYPE with type el = X.t)
是我能想到的最明显的表达方式 "give me a signature that's just like this one, but with an abstract type replaced with a concrete one (or differently-abstract in this case)"。但是,在这种情况下它在语法上是无效的(因为有括号)。去掉括号也不会导致有效的 "module-language-level expression";我保留它是因为我认为它使我的意图更加明显。
那么...您如何使用命名签名来限制对[仿函数产生的模块]/[参数化模块]的可见性?
如果你不想将el
添加到模块的导出中,那么有两种方法:
使用替代约束:
ORDERED_PAIR_SET_TYPE with type el := X.t
这将从签名中删除
el
的规范。使用参数化签名。不幸的是,这不能直接在 OCaml 中表达,但需要围绕签名的定义进行一些额外的仿函数操作:
module SET_TYPE (X : ORDERED_TYPE) = struct module type S = sig type t val get_fst : t -> X.el val get_snd : t -> X.el val make : X.el -> X.el -> t val compare : t -> t -> int end end
有了它你可以写:
module MakeOrderedPairSet (X : ORDERED_TYPE) : SET_TYPE(X).S = ...