From: Xavier Leroy <xleroy@pauillac.inria.fr>
Message-Id: <199603041405.PAA26261@pauillac.inria.fr>
Subject: Re: CSL modules
To: Guy.Cousineau@ens.fr
Date: Mon, 4 Mar 1996 15:05:49 +0100 (MET)
In-Reply-To: <9603011524.AA08384@aubepine.ens.fr> from "Guy.Cousineau@ens.fr" at Mar 1, 96 04:24:32 pm
> I would like to build a fonctor F such that  C=F(A,B)  "reexports"
> the  types and variables of A and B but with tb now being an abstract type.
> and ta remaining a concrete type .
> Moreover, I want C.xa to be a value of type C.ta and not a value of
> type A.ta which would be easy. The reason for that is that I do not
> want the users of my programs to see modules A and B but only module
> C.
This is easily done using a signature constraint to specify exactly
how much of C should remain visible:
module type SIGA =
  sig
    type ta = A | B of int
    val xa : ta
  end
module type SIGB =
  sig
    type tb = C | D of string
    val xb : tb
  end
module type SIGC =
  sig
    type ta = A | B of int      (* concrete *)
    type tb                     (* abstract *)
    val xa : ta
    val xb : tb
  end
module F(A: SIGA)(B: SIGB) =
  (struct
     type ta = A.ta = A | B of int
     type tb = B.tb
     let xa = A.xa
     let xb = B.xb
   end : SIGC)
module C = F(A)(B)
Notice the type definition "type ta = A.ta = A | B of int", which
keeps C.ta compatible with A.ta while re-exporting the constructors A
and B, which are now part of C. An alternate definition would be:
module type SIGC =
  sig
    type ta = A.ta              (* concrete *)
    type tb                     (* abstract *)
    val xa : ta
    val xb : tb
  end
module F(A: SIGA)(B: SIGB) =
  (struct
     type ta = A.ta
     type tb = B.tb
     let xa = A.xa
     let xb = B.xb
   end : SIGC)
module C = F(A)(B)
It is also correct, but not as good because A is not completely
hidden: the constructors of C.ta still come from A, not C. 
- Xavier Leroy