I have defined 2 signature and 4 modules as follows, and it works fine:
module type TRIANGLE =
sig
type 'a t
val get ...
val set ...
...
end
module type MATRIX =
sig
type 'a t
val unionArrayArray: 'a TriangleArray.t -> 'a TriangleArray.t -> 'a t
val unionListList: 'a TriangleList.t -> 'a TriangleList.t -> 'a t
val unionArrayList: 'a TriangleArray.t -> 'a TriangleList.t -> 'a t
val unionListArray: 'a TriangleList.t -> 'a TriangleArray.t -> 'a t
...
end
module rec MatrixArray: MATRIX =
struct
type 'a t = 'a array array
...
end
and MatrixList: MATRIX =
struct
type 'a t = 'a list list
...
end
and TriangleArray: TRIANGLE =
struct
type 'a t = 'a array array
...
end
and TriangleList: TRIANGLE =
struct
type 'a t = 'a list list
...
end
TRIANGLE
and MATRIX
are two parallel signatures. The function unionXXXX
takes two right triangles, if their sides have same length, builds a matrix.
The module XXXXArray
is internally realized by array of array, and the module XXXXList
is internally realized by list of list. But they could have same signature XXXX
which includes such functions as set
, get
...
The problem of this design is that, with the functions like set
, get
of TRIANGLE
, 4 unionXXXX
functions can have same implementation. We just need one function union
, and its type is actually : 'a TRIANGLE.t -> 'a TRIANGLE.t -> 'a MATRIX.t
.
But if I define the signature MATRIX
as follows, the compiler stops at the signature of union
and gives an Error: Unbound module Triangle
:
module type TRIANGLE =
sig
type 'a t
val get ...
val set ...
...
end
module type MATRIX =
sig
type 'a t
val union: 'a TRIANGLE.t -> 'a TRIANGLE.t -> 'a t
...
end
I hope I have shown it is better to combine 4 unionXXXX
functions to one union
, but it is really a pity that we can't specify its type, because of the lack of 'a TRIANGLE.t
, either in the signature MATRIX
or in the modules MatrixXXXX
.
I hope my need and concern has been clearly described, and does anyone have a solution or a better design?
Edit1 : change case of letters as the comment suggests...
First, a word on conventions : it's usually expected that module names have CamelCase
formatting and module type names have ALL_UPPERCASE
formatting. It took me two reads to notice you were dealing with module types instead of modules.
So, what you are trying to say here is that any module which implements module type MATRIX
should be able, for any module Triangle
that implements TRIANGLE
, provide this signature:
type 'a t
val union : 'a Triangle.t -> 'a Triangle.t -> 'a t
It's not possible to express universal quantifiers like that. What you should do is use an existential quantifier and a functor :
module type MATRIX = sig
module Triangle : TRIANGLE
type 'a t
val union : 'a Triangle.t -> 'a Triangle.t -> 'a t
end
module MatrixOfTriangle = functor (Triangle:TRIANGLE) -> struct
module Triangle = Triangle
type 'a t = ...
let union t1 t2 = ...
end
This does force you to specify what triangle you are working on at any given point in your code, but you can use functors with TRIANGLE
arguments to avoid settling on one type of triangle.
来源:https://stackoverflow.com/questions/9058035/need-and-impossibility-of-having-a-type-of-a-signature