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