caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] First class modules aliases
@ 2014-02-14  7:23 Christophe Troestler
  2014-02-14  8:57 ` Alain Frisch
       [not found] ` <20140215.152342.1020588167010524975.Christophe.Troestler@umons.ac.be>
  0 siblings, 2 replies; 7+ messages in thread
From: Christophe Troestler @ 2014-02-14  7:23 UTC (permalink / raw)
  To: OCaml Mailing List

Hi,

I have encoutered several annoyances with module aliasing in the
context of first class modules.  For example, if I declare

    module type A = sig type t end
    type 'a a = (module A with type t = 'a)
    module type IA = A with type t = int
    type ia = (module IA)

then I expect the types “int a” and “ia” to be equivalent but this is
not the case:

    let f (a: int a) = (a : ia)

gives the error

    This expression has type int a = (module A with type t = int)
    but an expression was expected of type ia = (module IA)

That's unfortunate because one may want to use the shortcut “IA” to
constraint various module types and still expect to be able to use the
general functions for “int a” on those.

Another example is:

    module X = struct
      module type T = sig type s end
      type 'a t = (module T with type s = 'a)
      let id (x: int t) = x
    end
    
    let f (x: int X.t) = x
    
    module Y = struct
      include X
      let h x = f(id x)
    end

To make it work, I basically have to perform by hand the aliasing that
“include X” should make:

    module Y : sig type 'a t  val h : int t -> int t end = struct
      type 'a t = 'a X.t
      let h x = f(X.id x)
    end

This problem makes modularity more difficult.

Are the above problems that one has to learn to live with when using
first class modules or may we expect the type checker to be able to
cope with them in the future?

Best,
C.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] First class modules aliases
  2014-02-14  7:23 [Caml-list] First class modules aliases Christophe Troestler
@ 2014-02-14  8:57 ` Alain Frisch
  2014-02-14  9:08   ` Jacques Garrigue
  2014-02-14  9:39   ` Alain Frisch
       [not found] ` <20140215.152342.1020588167010524975.Christophe.Troestler@umons.ac.be>
  1 sibling, 2 replies; 7+ messages in thread
From: Alain Frisch @ 2014-02-14  8:57 UTC (permalink / raw)
  To: Christophe Troestler, OCaml Mailing List

Hi Christophe,

On 02/14/2014 08:23 AM, Christophe Troestler wrote:
> I have encoutered several annoyances with module aliasing in the
> context of first class modules.  For example, if I declare
>
>      module type A = sig type t end
>      type 'a a = (module A with type t = 'a)
>      module type IA = A with type t = int
>      type ia = (module IA)
>
> then I expect the types “int a” and “ia” to be equivalent but this is
> not the case:
>
>      let f (a: int a) = (a : ia)
>
> gives the error
>
>      This expression has type int a = (module A with type t = int)
>      but an expression was expected of type ia = (module IA)

Indeed, two "package types" are equal (w.r.t. unification) if they have 
the same module type path (nominally, after expanding bare module type 
aliases) and the same list of constraints (modulo reordering).  In this 
case, module type paths are different (A and IA) and so are the lists of 
constraints (of respective length 1 and 0).

One could try to use a more relaxed definition of equality, based on 
actually comparing module type expressions.  At least for closed package 
types (i.e. for (module A with t = int) but not (module A with t = 'a)), 
this might be doable, although introducing a dependency between the 
unification algorithm and the equality check for module types might 
cause unexpected problems.

> Another example is:
>
>      module X = struct
>        module type T = sig type s end
>        type 'a t = (module T with type s = 'a)
>        let id (x: int t) = x
>      end
>
>      let f (x: int X.t) = x
>
>      module Y = struct
>        include X
>        let h x = f(id x)
>      end
>
> To make it work, I basically have to perform by hand the aliasing that
> “include X” should make:
>
>      module Y : sig type 'a t  val h : int t -> int t end = struct
>        type 'a t = 'a X.t
>        let h x = f(X.id x)
>      end

Here the problem is that "include X" copies the definition of the module 
type T, as if you had written:

   module T = sig type s end

and thus it introduces a new module type path.  Since package types use 
a nominal equality between module type paths, (module T) and (module 
X.T) are incompatible.   One way to fix it would be to tweak the 
"strengthening" algorithm which adds equalities to module types in order 
to turn a module type declaration to an alias to the original definition 
instead of copying it.  Concretely, one would change in 
Mtype.strengthen_sig:


   | Sig_modtype(id, decl) :: rem ->
       let newdecl =
         match decl.mtd_type with
           None ->
             {decl with mtd_type = Some(Mty_ident(Pdot(p, Ident.name id, 
nopos)))}
         | Some _ ->
             decl
       in
       ...

into:

   | Sig_modtype(id, decl) :: rem ->
       let newdecl =
             {decl with mtd_type = Some(Mty_ident(Pdot(p, Ident.name id, 
nopos)))}
       in
       ...

Since module type paths are interpreted nominally (for first-class 
modules), it could indeed make sense to keep the equation like that.

But maybe there are unfortunate consequences of doing so.  I hope that 
our usual experts of the type system will comment!



Alain

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] First class modules aliases
  2014-02-14  8:57 ` Alain Frisch
@ 2014-02-14  9:08   ` Jacques Garrigue
  2014-02-14  9:22     ` Alain Frisch
  2014-02-14  9:39   ` Alain Frisch
  1 sibling, 1 reply; 7+ messages in thread
From: Jacques Garrigue @ 2014-02-14  9:08 UTC (permalink / raw)
  To: Alain Frisch; +Cc: Christophe Troestler, OCaml Mailing List

On 2014/02/14 17:57, Alain Frisch wrote:

> Hi Christophe,
> 
> On 02/14/2014 08:23 AM, Christophe Troestler wrote:
>> I have encoutered several annoyances with module aliasing in the
>> context of first class modules.  For example, if I declare
>> 
>>     module type A = sig type t end
>>     type 'a a = (module A with type t = 'a)
>>     module type IA = A with type t = int
>>     type ia = (module IA)
>> 
>> then I expect the types “int a” and “ia” to be equivalent but this is
>> not the case:
>> 
>>     let f (a: int a) = (a : ia)
>> 
>> gives the error
>> 
>>     This expression has type int a = (module A with type t = int)
>>     but an expression was expected of type ia = (module IA)
> 
> Indeed, two "package types" are equal (w.r.t. unification) if they have the same module type path (nominally, after expanding bare module type aliases) and the same list of constraints (modulo reordering).  In this case, module type paths are different (A and IA) and so are the lists of constraints (of respective length 1 and 0).
> 
> One could try to use a more relaxed definition of equality, based on actually comparing module type expressions.  At least for closed package types (i.e. for (module A with t = int) but not (module A with t = 'a)), this might be doable, although introducing a dependency between the unification algorithm and the equality check for module types might cause unexpected problems.

Moscow ML uses this relaxed equality, and this does not seem to be a problem.
However, this requires some care when handling free variables.

>> Another example is:
>> 
>>     module X = struct
>>       module type T = sig type s end
>>       type 'a t = (module T with type s = 'a)
>>       let id (x: int t) = x
>>     end
>> 
>>     let f (x: int X.t) = x
>> 
>>     module Y = struct
>>       include X
>>       let h x = f(id x)
>>     end
>> 
>> To make it work, I basically have to perform by hand the aliasing that
>> “include X” should make:
>> 
>>     module Y : sig type 'a t  val h : int t -> int t end = struct
>>       type 'a t = 'a X.t
>>       let h x = f(X.id x)
>>     end
> 
> Here the problem is that "include X" copies the definition of the module type T, as if you had written:
> 
>  module T = sig type s end
> 
> and thus it introduces a new module type path.  Since package types use a nominal equality between module type paths, (module T) and (module X.T) are incompatible.   One way to fix it would be to tweak the "strengthening" algorithm which adds equalities to module types in order to turn a module type declaration to an alias to the original definition instead of copying it.  

This is already done in trunk.

Jacques Garrigue

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] First class modules aliases
  2014-02-14  9:08   ` Jacques Garrigue
@ 2014-02-14  9:22     ` Alain Frisch
  2014-02-14 23:23       ` Jacques Garrigue
  0 siblings, 1 reply; 7+ messages in thread
From: Alain Frisch @ 2014-02-14  9:22 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: Christophe Troestler, OCaml Mailing List

On 02/14/2014 10:08 AM, Jacques Garrigue wrote:
 > On 2014/02/14 17:57, Alain Frisch wrote:
>>    One way to fix it would be to tweak the "strengthening" algorithm 
which adds equalities to module types in order to turn a module type 
declaration to an alias to the original definition instead of copying it.
>
> This is already done in trunk.

Are you sure?  I don't see it.  We're talking about keeping equations 
for module type declarations, not for module declarations, right?

-- Alain


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] First class modules aliases
  2014-02-14  8:57 ` Alain Frisch
  2014-02-14  9:08   ` Jacques Garrigue
@ 2014-02-14  9:39   ` Alain Frisch
  1 sibling, 0 replies; 7+ messages in thread
From: Alain Frisch @ 2014-02-14  9:39 UTC (permalink / raw)
  To: Christophe Troestler, OCaml Mailing List

On 02/14/2014 09:57 AM, Alain Frisch wrote:
>  One way to fix it would be to tweak the
> "strengthening" algorithm which adds equalities to module types in order
> to turn a module type declaration to an alias to the original definition
> instead of copying it.

Another example which is fixed by this patch is the following (reported 
by my colleague David Waern):

==============================================
module M =
   struct
     module type T = sig type t end
     type t = (module T)
   end

module type X =
   sig
     module K: sig type t end
   end

module Make(A : sig type t end)(X: X with type K.t = A.t) = struct end

module Z = Make(M)(struct module K = M end)
==============================================


-- Alain

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] First class modules aliases
  2014-02-14  9:22     ` Alain Frisch
@ 2014-02-14 23:23       ` Jacques Garrigue
  0 siblings, 0 replies; 7+ messages in thread
From: Jacques Garrigue @ 2014-02-14 23:23 UTC (permalink / raw)
  To: Alain Frisch; +Cc: Christophe Troestler, OCaml Mailing List

On 2014/02/14 18:22, Alain Frisch wrote:

> On 02/14/2014 10:08 AM, Jacques Garrigue wrote:
> > On 2014/02/14 17:57, Alain Frisch wrote:
>>>   One way to fix it would be to tweak the "strengthening" algorithm 
> which adds equalities to module types in order to turn a module type declaration to an alias to the original definition instead of copying it.
>> 
>> This is already done in trunk.
> 
> Are you sure?  I don't see it.  We're talking about keeping equations for module type declarations, not for module declarations, right?

Sorry, I got confused.
What trunk does is allowing to use aliases of module types in first class modules.
This was not allowed before.
What you suggest is also introducing aliases in place of copying for module types when using include.
This would be useless without the previous change, but makes sense with it.

	Jacques

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] First class modules from C
       [not found] ` <20140215.152342.1020588167010524975.Christophe.Troestler@umons.ac.be>
@ 2014-02-15 15:05   ` Alain Frisch
  0 siblings, 0 replies; 7+ messages in thread
From: Alain Frisch @ 2014-02-15 15:05 UTC (permalink / raw)
  To: Christophe Troestler, OCaml Mailing List

On 2/15/2014 3:23 PM, Christophe Troestler wrote:
> When passing a packed module to a C function, do we access its values
> as if it was a record (in the order of the signature) or is it more
> complicated?  A description in the user manual would be nice!

Yes, currently, this is how a first-class module is represented, and you 
need to know exactly what in the signature count for one slot.  But this 
representation is not specified, and not guaranteed to remain like that 
in future  versions (in particular, it might very well be the case that 
first-class modules would receive an extra unique identifier field, to 
be used by the generic hash/compare functions).  It seems more robust to 
access components from an OCaml function (called from C, if needed, or 
applied before/instead passing the packed module to C).


-- Alain

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2014-02-15 15:06 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-14  7:23 [Caml-list] First class modules aliases Christophe Troestler
2014-02-14  8:57 ` Alain Frisch
2014-02-14  9:08   ` Jacques Garrigue
2014-02-14  9:22     ` Alain Frisch
2014-02-14 23:23       ` Jacques Garrigue
2014-02-14  9:39   ` Alain Frisch
     [not found] ` <20140215.152342.1020588167010524975.Christophe.Troestler@umons.ac.be>
2014-02-15 15:05   ` [Caml-list] First class modules from C Alain Frisch

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).