Reputation: 3088
OCaml doesn't provide the ability to create a module type by functor directly. But, It allows some manipulations with the nested module type. So, I can use module type from parameter to bind module type in the result:
module CONTAINER = struct
module type S = sig
val a : int
end
end
module COPY (CONTAINER : sig module type S end) = struct
module type S = CONTAINER.S
end
module type S_FROM_CONTAINER = COPY(CONTAINER).S
S_FROM_CONTAINER
isn't abstract. It is necessary to provide a
to apply S_FROM_CONTAINER
.
(*
module Impl : S_FROM_CONTAINER = struct
end
> Error: Signature mismatch:
> Modules do not match: sig end is not included in S_FROM_CONTAINER
> The value `a' is required but not provided
*)
module Impl : S_FROM_CONTAINER = struct
let a = 42
end
Also, I can use S
from CONTAINER
as a type of module in module type in the resulting module:
module AS_TYPE_OF_IMPL (CONTAINER : sig module type S end) = struct
module type S = sig
module Impl : CONTAINER.S
end
end
module type IMPL_CONTAINER_S =
AS_TYPE_OF_IMPL(CONTAINER).S
Impl
module in IMPL_CONTAINER_S
isn't abstract module type too:
(* module ImplContainer : IMPL_CONTAINER_S = struct
module Impl = struct end
end
> Error: Signature mismatch:
> Modules do not match:
> sig module Impl : sig end end
> is not included in
> IMPL_CONTAINER_S
> In module Impl:
> Modules do not match: sig end is not included in CONTAINER.S
> In module Impl:
> The value `a' is required but not provided
*)
module ImplContainer : IMPL_CONTAINER_S = struct
module Impl = struct let a = 42 end
end
That's fine. I think it is a powerful tool. But I found one limitation that makes me sad. It is impossible to include this module type into another one.
module EXTEND_S (CONTAINER : sig module type S end) = struct
module type S = sig
include CONTAINER.S
val extention : int
end
end
Or
module AS_PART_OF_IMPL (CONTAINER : sig module type S end) = struct
module type S = sig
module Impl : sig
include CONTAINER.S
val extention : int
end
end
end
include CONTAINER.S
^^^^^^^^^^^
Error: This module type is not a signature
Why I can't do this? For me, it looks like some gap, nor only in the compiler but in language conception too. What I miss to understand?
Upvotes: 1
Views: 939
Reputation: 18892
In brief, include
are not part of the type system of modules and they work on signatures by inlining the content of the signature. And adding an include
expression in the module system is not that straightforward because one cannot include any module type in any context. Consider for instance:
module F(X:sig module type x module type y end) = struct
module type result = sig
include x
include y
end
end
is not always valid. Consider for instance,
module type x = sig
type t
val x: t
end
module type y = sig
type t
val y: t
end
then
module type t = sig
include x
include y
end
yields an error
Error: Illegal shadowing of included type t/863 by t/865 Line 2, characters 2-11: Type t/863 came from this include Line 3, characters 2-10: The value x has no valid type if t/863 is shadowed
Thus include s
is not always valid and making it possible to include abstract type module would require to refine the module type system to capture this condition.
Moreover, having module types with a dynamic number of runtime components would require a different compilation scheme because querying a path inside a module can no longer be reduced to querying a statistically-known index in a block.
Upvotes: 3