OCaml中的仿函数设计

时间:2012-12-18 16:50:45

标签: ocaml functor

我已经定义了2个模块ZoneZonesZonesZone的列表,Zones的原因函数需要调用{的函数{1}}:

Zone

原则文件module Zone = struct type t = { ... prop: bool } ... end modules Zones = struct type t = | ZSbot | ZS of Zone.t list | ZStop ... end 使用all.mlZones个模块,Mis包含适用于mis.mlZone.t的函数Zones.t

val Mis.make : Zone.t -> Zones.t

现在,我想为open Zones open Mis type t = { zs: Zones.t } ... Mis.make z 的{​​{1}}提供更多选项。所以我定义了一个界面prop和2个模块ZonePROPERTY匹配它,这样我就可以为TypeFormula的其他人创建仿函数。现在我可以想象新Zone

的几种可能性
... prop: Property.t ...

虽然all.ml(* 1 *) open Zones module ZonesType = ZonesFun(Type) module ZonesFormula = ZonesFun(Formula) type t = { zstype: ZonesType.t; zsformula: ZonesFormula } (* 3 *) open Zones module ZonesType = ZonesFun(ZoneFun(Type)) module ZonesFormula = ZonesFun(ZoneFun(Formula)) type t = { zstype: ZonesType.t; zsformula: ZonesFormula } (* 4 *) open Zones module ZoneType = ZoneFun(Type) module ZoneFormula = ZoneFun(Formula) module ZonesType = ZonesFun(ZoneType) module ZonesFormula = ZonesFun(ZoneFormula) type t = { zstype: ZonesType.t; zsformula: ZonesFormula } 的签名在3个选项中有所不同,但此实施可确保ZonesFunZoneFun一致。现在一个大问题是如何更改ZoneXXX.t

1)如果我制作一个仿函数ZonesXXX.t,并在里面构建MisMisFun: PROPERTY -> MIS。无法知道ZoneXXXZonesXXX的{​​{1}}相同,或MisXXX.Zone.tZone.t的{​​{1}}相同。

2)如果我制作仿函数all.ml,则无法知道MisXXX.Zones.tZones.t是否一致。

有谁知道如何解决1)和2)?

1 个答案:

答案 0 :(得分:3)

在选项(1)中,您是否在ZoneFun内申请了ZonesFun

假设,我认为选择在(1)和(3)/(4)之间(看起来是相同的)。选择哪一个取决于您是否需要能够访问Zone之外创建的ZoneFun模块(您需要(4))或不((1)正常工作)。

更新回复更新:

如果我理解你的问题,那么在我看来Mis也必须成为一个仿函数。此外,它的签名可以指定类型

val make: ZoneFun(X).t -> ZonesFun(X).t

其中X是函子参数。

(顺便说一句,除了你命名辅助模块外,我仍然认为(3)和(4)没有区别。)

更新2:

我的猜测是你在OCaml的模块类型检查器中遇到了一个旧的和不幸的错误(参见this discussion on the caml list)。以下应该工作,但不是:

module type PROP = sig type t end
module type ZONE = sig type t end
module MakeZone (P : PROP) = struct type t = {p : P.t} end
module MakeZones (Z : ZONE) = struct type t = ZS of Z.t list end

module MakeMisc (P : PROP) :
sig
  val make : MakeZone(P).t -> MakeZones(MakeZone(P)).t
end =
struct
  module Zone = MakeZone(P)
  module Zones = MakeZones(Zone)
  let make z = Zones.ZS [z]
end

module Type = struct type t = T end
module Formula = struct type t = F end
module ZoneType = MakeZone(Type)
module ZoneFormula = MakeZone(Formula)
module ZonesType = MakeZones(ZoneType)
module ZonesFormula = MakeZones(ZoneFormula)
module MiscType = MakeMisc(Type)
module MiscFormula = MakeMisc(Formula)
let zst = MiscType.make {ZoneType.p = Type.T}
let zsf = MiscFormula.make {ZoneFormula.p = Formula.F}

您可以通过在MakeMisc中添加类型注释来强制使其工作,如下所示:

module MakeMisc (P : PROP) :
sig
  val make : MakeZone(P).t -> MakeZones(MakeZone(P)).t
end =
struct
  module Zone : sig type t = MakeZone(P).t end = MakeZone(P)
  module Zones :
    sig type t = MakeZones(MakeZone(P)).t = ZS of MakeZone(P).t list end =
    MakeZones(MakeZone(P))
  let make z = Zones.ZS [z]
end

但显然,这不是很愉快。

但是,无论如何,在ML中表达共享的常用方法是通过 fibration ,您可以在签名中抽象地命名要共享的类型或模块,并相应地对其进行优化。然后,您可以将ZoneZones转换为Misc仿函数的其他参数:

module type PROP = sig type t end
module type ZONE = sig type prop type t = {p : prop} end
module type ZONES = sig type zone type t = ZS of zone list end
module MakeZone (P : PROP) = struct type prop = P.t type t = {p : prop} end
module MakeZones (Z : ZONE) = struct type zone = Z.t type t = ZS of zone list end

module MakeMisc
  (P : PROP) (Z : ZONE with type prop = P.t) (Zs : ZONES with type zone = Z.t) :
sig
  val make : Z.t -> Zs.t
end =
struct
  let make z = Zs.ZS [z]
end

module Type = struct type t = T end
module Formula = struct type t = F end
module ZoneType = MakeZone(Type)
module ZoneFormula = MakeZone(Formula)
module ZonesType = MakeZones(ZoneType)
module ZonesFormula = MakeZones(ZoneFormula)
module MiscType = MakeMisc(Type)(ZoneType)(ZonesType)
module MiscFormula = MakeMisc(Formula)(ZoneFormula)(ZonesFormula)
let zst = MiscType.make {ZoneType.p = Type.T}
let zsf = MiscFormula.make {ZoneFormula.p = Formula.F}