Need and impossibility of having a type of a signa

2019-04-16 00:36发布

问题:

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...

回答1:

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.