I have defined 2 modules Zone
and Zones
, Zones
is a list of Zone
, of cause functions of Zones
need to call functions of Zone
:
module Zone = struct
type t =
{ ...
prop: bool }
...
end
modules Zones = struct
type t =
| ZSbot
| ZS of Zone.t list
| ZStop
...
end
A principle file all.ml
uses Zones
and Mis
modules, mis.ml
contains functions which work on both Zone.t
and Zones.t
, for instance val Mis.make : Zone.t -> Zones.t
.
open Zones
open Mis
type t = { zs: Zones.t }
...
Mis.make z
Now, I would like to have more options for the prop
of Zone
. So I define an interface PROPERTY
and 2 modules Type
and Formula
matching it, so that I can make functors for Zone
and others where ... prop: Property.t ...
. Now I can imagine several possibilities for the new 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 }
Although the signatures of ZonesFun
and ZoneFun
are different among the 3 options, this implementation can make sure ZoneXXX.t
and ZonesXXX.t
are coherent. Now one big problem is how to change Mis
:
1) If I make a functor MisFun: PROPERTY -> MIS
, and build the ZoneXXX
and ZonesXXX
inside. It cannot know MisXXX.Zone.t
is same as Zone.t
of all.ml
, or MisXXX.Zones.t
is same as Zones.t
of all.ml
.
2) If I make a functor MisFun: Zone -> Zones -> MIS
, it cannot know MisXXX.Zone.t
and MisXXX.Zones.t
are coherent.
Does anyone know how to solve both 1) and 2)?
In Option (1), do you apply ZoneFun
inside ZonesFun
?
Assuming that, I think the choice is between (1) and (3)/(4) (which seem to be the same). Which one to pick depends on whether you need to be able to access the created Zone
modules outside ZoneFun
(you need (4)) or not ((1) works fine).
Update in reply to update:
If I understand your question correctly, then it seems to me that Mis
has to become a functor as well. Moreover, its signature can specify types like
val make: ZoneFun(X).t -> ZonesFun(X).t
where X
is the functor parameter.
(Btw, I still see no difference between (3) and (4), except that you name the auxiliary modules.)
Update 2:
My guess is that you are running into an old and unfortunate bug in OCaml's module type checker (see this discussion on the caml list). The following ought to work, but doesn't:
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}
You can force to make it work by putting in type annotations in MakeMisc
as follows:
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
But obviously, that's not very pleasant.
However, the common way to express sharing in ML, anyway, is by fibration, where you name the types or modules you want to share with abstractly in the signatures and refine them accordingly. Then you can turn Zone
and Zones
into additional parameters of the Misc
functor:
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}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With