caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Weird type error involving 'include' and applicative functors
@ 2015-02-13 21:40 Carl Eastlund
  2015-02-15 10:26 ` Gabriel Scherer
  0 siblings, 1 reply; 8+ messages in thread
From: Carl Eastlund @ 2015-02-13 21:40 UTC (permalink / raw)
  To: caml-list

[-- Attachment #1: Type: text/plain, Size: 1730 bytes --]

This seems to be a compiler bug, but let me know if I've missed something.
The behavior I see is that Make_ok1 and Make_ok2 compile fine, but the very
similar functor Make_bad does not.  I get this compile error:

========================================

      Error: Signature mismatch:
             Modules do not match:
               sig
                 module C : sig module T : sig  end type t = Make(T).t end
                 module T = C.T
                 type t = Make(T).t
               end
             is not included in
               sig type t module C : sig type t = t end end
             In module C:
             Modules do not match:
               sig module T : sig  end type t = Make(T).t end
             is not included in
               sig type t = C.t end
             In module C:
             Type declarations do not match:
               type t = Make(T).t
             is not included in
               type t = t

========================================

And here is the code:

========================================

module type S = sig type t end
module Make (M : sig end) : S = struct type t end

module Make_ok1 (M : sig end) : sig

  type t
  module A : S with type t = t

end = struct

  module A = struct
    include Make (struct end)
  end
  include A

end

module Make_ok2 (M : sig end) : sig

  type t
  module B : S with type t = t

end = struct

  module T = struct end
  module B = struct
    include Make (T)
  end
  include B

end

module Make_bad (M : sig end) : sig

  type t
  module C : S with type t = t

end = struct

  module C = struct
    module T = struct end
    include Make (T)
  end
  include C

end

========================================

--
Carl Eastlund

[-- Attachment #2: Type: text/html, Size: 2855 bytes --]

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

* Re: [Caml-list] Weird type error involving 'include' and applicative functors
  2015-02-13 21:40 [Caml-list] Weird type error involving 'include' and applicative functors Carl Eastlund
@ 2015-02-15 10:26 ` Gabriel Scherer
  2015-02-16 18:03   ` Leo White
  2015-02-24  4:38   ` Jacques Garrigue
  0 siblings, 2 replies; 8+ messages in thread
From: Gabriel Scherer @ 2015-02-15 10:26 UTC (permalink / raw)
  To: Carl Eastlund; +Cc: caml users

That is one of the dark corners of the module system.

I don't know whether an ideal type-checker should accept your last
definition or not. It is non-intuitive that some are accepted and
others rejected; some things in the module system are non-intuitive
for good reasons, some others because of implementation limitations,
and it's not always clear to non-experts which is which).˙But I can
explain why the last definition is harder for the type-checker to
accept than the other.

# module A = struct
  module T = struct end
  module C = struct
    include Make(T)
  end
  include C
end
;;
module A :
  sig
    module T : sig  end
    module C : sig type t = Make(T).t end
    type t = Make(T).t
  end

# module B = struct
  module C = struct
    module T = struct end
    include Make(T)
  end
  include C
end
;;
module B :
  sig
    module C : sig module T : sig  end type t = Make(T).t end
    module T = C.T
    type t = Make(T).t
  end


Note the important difference in the inferred signatures in both
cases. Both modules have
    type t = Make(T).t
but, in the first case, this is the *same module T* that is mentioned
in the signature of T, while in the second case, there are two
different modules, C.T and T (the latter being generated by the
"include", with an equation that it is equal to the former).

The reasoning to check against your signature
  sig
    type t
    module C : S with type t = t
  end
is thus more complicated in the second case: the type-checker would
need to use the equation (T = C.T) to check that indeed C.t is equal
to t.

I think this is due to the rather contorted way you define C first in
the implementations and include it later, while in the signature first
define t and then C. Note that the following signature, which is
morally equivalent, accepts both implementations (and thus all the
functors in your file):
  sig
    module C : S
    type t = C.t
  end


On Fri, Feb 13, 2015 at 10:40 PM, Carl Eastlund
<ceastlund@janestreet.com> wrote:
> This seems to be a compiler bug, but let me know if I've missed something.
> The behavior I see is that Make_ok1 and Make_ok2 compile fine, but the very
> similar functor Make_bad does not.  I get this compile error:
>
> ========================================
>
>       Error: Signature mismatch:
>              Modules do not match:
>                sig
>                  module C : sig module T : sig  end type t = Make(T).t end
>                  module T = C.T
>                  type t = Make(T).t
>                end
>              is not included in
>                sig type t module C : sig type t = t end end
>              In module C:
>              Modules do not match:
>                sig module T : sig  end type t = Make(T).t end
>              is not included in
>                sig type t = C.t end
>              In module C:
>              Type declarations do not match:
>                type t = Make(T).t
>              is not included in
>                type t = t
>
> ========================================
>
> And here is the code:
>
> ========================================
>
> module type S = sig type t end
> module Make (M : sig end) : S = struct type t end
>
> module Make_ok1 (M : sig end) : sig
>
>   type t
>   module A : S with type t = t
>
> end = struct
>
>   module A = struct
>     include Make (struct end)
>   end
>   include A
>
> end
>
> module Make_ok2 (M : sig end) : sig
>
>   type t
>   module B : S with type t = t
>
> end = struct
>
>   module T = struct end
>   module B = struct
>     include Make (T)
>   end
>   include B
>
> end
>
> module Make_bad (M : sig end) : sig
>
>   type t
>   module C : S with type t = t
>
> end = struct
>
>   module C = struct
>     module T = struct end
>     include Make (T)
>   end
>   include C
>
> end
>
> ========================================
>
> --
> Carl Eastlund

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

* Re: [Caml-list] Weird type error involving 'include' and applicative functors
  2015-02-15 10:26 ` Gabriel Scherer
@ 2015-02-16 18:03   ` Leo White
  2015-02-17 21:40     ` Milan Stanojević
  2015-02-24  4:38   ` Jacques Garrigue
  1 sibling, 1 reply; 8+ messages in thread
From: Leo White @ 2015-02-16 18:03 UTC (permalink / raw)
  To: Gabriel Scherer; +Cc: Carl Eastlund, caml users

Gabriel gives an accurate accout of what is going on. To me, it looks
like the type-checker should probably accept this, so I would submit it
as a bug (I suspect a missing call to Env.normalize_path somewhere, but
perhaps there is something more significant going on here).

Regards,

Leo

Gabriel Scherer <gabriel.scherer@gmail.com> writes:

> That is one of the dark corners of the module system.
>
> I don't know whether an ideal type-checker should accept your last
> definition or not. It is non-intuitive that some are accepted and
> others rejected; some things in the module system are non-intuitive
> for good reasons, some others because of implementation limitations,
> and it's not always clear to non-experts which is which).˙But I can
> explain why the last definition is harder for the type-checker to
> accept than the other.
>
> # module A = struct
>   module T = struct end
>   module C = struct
>     include Make(T)
>   end
>   include C
> end
> ;;
> module A :
>   sig
>     module T : sig  end
>     module C : sig type t = Make(T).t end
>     type t = Make(T).t
>   end
>
> # module B = struct
>   module C = struct
>     module T = struct end
>     include Make(T)
>   end
>   include C
> end
> ;;
> module B :
>   sig
>     module C : sig module T : sig  end type t = Make(T).t end
>     module T = C.T
>     type t = Make(T).t
>   end
>
>
> Note the important difference in the inferred signatures in both
> cases. Both modules have
>     type t = Make(T).t
> but, in the first case, this is the *same module T* that is mentioned
> in the signature of T, while in the second case, there are two
> different modules, C.T and T (the latter being generated by the
> "include", with an equation that it is equal to the former).
>
> The reasoning to check against your signature
>   sig
>     type t
>     module C : S with type t = t
>   end
> is thus more complicated in the second case: the type-checker would
> need to use the equation (T = C.T) to check that indeed C.t is equal
> to t.
>
> I think this is due to the rather contorted way you define C first in
> the implementations and include it later, while in the signature first
> define t and then C. Note that the following signature, which is
> morally equivalent, accepts both implementations (and thus all the
> functors in your file):
>   sig
>     module C : S
>     type t = C.t
>   end
>
>
> On Fri, Feb 13, 2015 at 10:40 PM, Carl Eastlund
> <ceastlund@janestreet.com> wrote:
>> This seems to be a compiler bug, but let me know if I've missed something.
>> The behavior I see is that Make_ok1 and Make_ok2 compile fine, but the very
>> similar functor Make_bad does not.  I get this compile error:
>>
>> ========================================
>>
>>       Error: Signature mismatch:
>>              Modules do not match:
>>                sig
>>                  module C : sig module T : sig  end type t = Make(T).t end
>>                  module T = C.T
>>                  type t = Make(T).t
>>                end
>>              is not included in
>>                sig type t module C : sig type t = t end end
>>              In module C:
>>              Modules do not match:
>>                sig module T : sig  end type t = Make(T).t end
>>              is not included in
>>                sig type t = C.t end
>>              In module C:
>>              Type declarations do not match:
>>                type t = Make(T).t
>>              is not included in
>>                type t = t
>>
>> ========================================
>>
>> And here is the code:
>>
>> ========================================
>>
>> module type S = sig type t end
>> module Make (M : sig end) : S = struct type t end
>>
>> module Make_ok1 (M : sig end) : sig
>>
>>   type t
>>   module A : S with type t = t
>>
>> end = struct
>>
>>   module A = struct
>>     include Make (struct end)
>>   end
>>   include A
>>
>> end
>>
>> module Make_ok2 (M : sig end) : sig
>>
>>   type t
>>   module B : S with type t = t
>>
>> end = struct
>>
>>   module T = struct end
>>   module B = struct
>>     include Make (T)
>>   end
>>   include B
>>
>> end
>>
>> module Make_bad (M : sig end) : sig
>>
>>   type t
>>   module C : S with type t = t
>>
>> end = struct
>>
>>   module C = struct
>>     module T = struct end
>>     include Make (T)
>>   end
>>   include C
>>
>> end
>>
>> ========================================
>>
>> --
>> Carl Eastlund

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

* Re: [Caml-list] Weird type error involving 'include' and applicative functors
  2015-02-16 18:03   ` Leo White
@ 2015-02-17 21:40     ` Milan Stanojević
  2015-02-19 18:21       ` Milan Stanojević
  0 siblings, 1 reply; 8+ messages in thread
From: Milan Stanojević @ 2015-02-17 21:40 UTC (permalink / raw)
  To: Leo White; +Cc: Gabriel Scherer, Carl Eastlund, caml users

It seems that type checker does know that C.T and T are aliases since
this compiles

  module C = struct
    module T = struct end
    include Make (T)
  end
  include C

  let f (x : Make(Make(T)).t) : Make(Make(C.T)).t = x

Somehow the fact that C.T = T is lost when checking against the signature.




On Mon, Feb 16, 2015 at 1:03 PM, Leo White <lpw25@cam.ac.uk> wrote:
> Gabriel gives an accurate accout of what is going on. To me, it looks
> like the type-checker should probably accept this, so I would submit it
> as a bug (I suspect a missing call to Env.normalize_path somewhere, but
> perhaps there is something more significant going on here).
>
> Regards,
>
> Leo
>
> Gabriel Scherer <gabriel.scherer@gmail.com> writes:
>
>> That is one of the dark corners of the module system.
>>
>> I don't know whether an ideal type-checker should accept your last
>> definition or not. It is non-intuitive that some are accepted and
>> others rejected; some things in the module system are non-intuitive
>> for good reasons, some others because of implementation limitations,
>> and it's not always clear to non-experts which is which).˙But I can
>> explain why the last definition is harder for the type-checker to
>> accept than the other.
>>
>> # module A = struct
>>   module T = struct end
>>   module C = struct
>>     include Make(T)
>>   end
>>   include C
>> end
>> ;;
>> module A :
>>   sig
>>     module T : sig  end
>>     module C : sig type t = Make(T).t end
>>     type t = Make(T).t
>>   end
>>
>> # module B = struct
>>   module C = struct
>>     module T = struct end
>>     include Make(T)
>>   end
>>   include C
>> end
>> ;;
>> module B :
>>   sig
>>     module C : sig module T : sig  end type t = Make(T).t end
>>     module T = C.T
>>     type t = Make(T).t
>>   end
>>
>>
>> Note the important difference in the inferred signatures in both
>> cases. Both modules have
>>     type t = Make(T).t
>> but, in the first case, this is the *same module T* that is mentioned
>> in the signature of T, while in the second case, there are two
>> different modules, C.T and T (the latter being generated by the
>> "include", with an equation that it is equal to the former).
>>
>> The reasoning to check against your signature
>>   sig
>>     type t
>>     module C : S with type t = t
>>   end
>> is thus more complicated in the second case: the type-checker would
>> need to use the equation (T = C.T) to check that indeed C.t is equal
>> to t.
>>
>> I think this is due to the rather contorted way you define C first in
>> the implementations and include it later, while in the signature first
>> define t and then C. Note that the following signature, which is
>> morally equivalent, accepts both implementations (and thus all the
>> functors in your file):
>>   sig
>>     module C : S
>>     type t = C.t
>>   end
>>
>>
>> On Fri, Feb 13, 2015 at 10:40 PM, Carl Eastlund
>> <ceastlund@janestreet.com> wrote:
>>> This seems to be a compiler bug, but let me know if I've missed something.
>>> The behavior I see is that Make_ok1 and Make_ok2 compile fine, but the very
>>> similar functor Make_bad does not.  I get this compile error:
>>>
>>> ========================================
>>>
>>>       Error: Signature mismatch:
>>>              Modules do not match:
>>>                sig
>>>                  module C : sig module T : sig  end type t = Make(T).t end
>>>                  module T = C.T
>>>                  type t = Make(T).t
>>>                end
>>>              is not included in
>>>                sig type t module C : sig type t = t end end
>>>              In module C:
>>>              Modules do not match:
>>>                sig module T : sig  end type t = Make(T).t end
>>>              is not included in
>>>                sig type t = C.t end
>>>              In module C:
>>>              Type declarations do not match:
>>>                type t = Make(T).t
>>>              is not included in
>>>                type t = t
>>>
>>> ========================================
>>>
>>> And here is the code:
>>>
>>> ========================================
>>>
>>> module type S = sig type t end
>>> module Make (M : sig end) : S = struct type t end
>>>
>>> module Make_ok1 (M : sig end) : sig
>>>
>>>   type t
>>>   module A : S with type t = t
>>>
>>> end = struct
>>>
>>>   module A = struct
>>>     include Make (struct end)
>>>   end
>>>   include A
>>>
>>> end
>>>
>>> module Make_ok2 (M : sig end) : sig
>>>
>>>   type t
>>>   module B : S with type t = t
>>>
>>> end = struct
>>>
>>>   module T = struct end
>>>   module B = struct
>>>     include Make (T)
>>>   end
>>>   include B
>>>
>>> end
>>>
>>> module Make_bad (M : sig end) : sig
>>>
>>>   type t
>>>   module C : S with type t = t
>>>
>>> end = struct
>>>
>>>   module C = struct
>>>     module T = struct end
>>>     include Make (T)
>>>   end
>>>   include C
>>>
>>> end
>>>
>>> ========================================
>>>
>>> --
>>> Carl Eastlund
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs

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

* Re: [Caml-list] Weird type error involving 'include' and applicative functors
  2015-02-17 21:40     ` Milan Stanojević
@ 2015-02-19 18:21       ` Milan Stanojević
  2015-02-19 18:23         ` Milan Stanojević
  0 siblings, 1 reply; 8+ messages in thread
From: Milan Stanojević @ 2015-02-19 18:21 UTC (permalink / raw)
  To: Leo White; +Cc: Gabriel Scherer, Carl Eastlund, caml users

I submitted a bug report.
http://caml.inria.fr/mantis/view.php?id=6788


On Tue, Feb 17, 2015 at 4:40 PM, Milan Stanojević <milanst@gmail.com> wrote:
> It seems that type checker does know that C.T and T are aliases since
> this compiles
>
>   module C = struct
>     module T = struct end
>     include Make (T)
>   end
>   include C
>
>   let f (x : Make(Make(T)).t) : Make(Make(C.T)).t = x
>
> Somehow the fact that C.T = T is lost when checking against the signature.
>
>
>
>
> On Mon, Feb 16, 2015 at 1:03 PM, Leo White <lpw25@cam.ac.uk> wrote:
>> Gabriel gives an accurate accout of what is going on. To me, it looks
>> like the type-checker should probably accept this, so I would submit it
>> as a bug (I suspect a missing call to Env.normalize_path somewhere, but
>> perhaps there is something more significant going on here).
>>
>> Regards,
>>
>> Leo
>>
>> Gabriel Scherer <gabriel.scherer@gmail.com> writes:
>>
>>> That is one of the dark corners of the module system.
>>>
>>> I don't know whether an ideal type-checker should accept your last
>>> definition or not. It is non-intuitive that some are accepted and
>>> others rejected; some things in the module system are non-intuitive
>>> for good reasons, some others because of implementation limitations,
>>> and it's not always clear to non-experts which is which).˙But I can
>>> explain why the last definition is harder for the type-checker to
>>> accept than the other.
>>>
>>> # module A = struct
>>>   module T = struct end
>>>   module C = struct
>>>     include Make(T)
>>>   end
>>>   include C
>>> end
>>> ;;
>>> module A :
>>>   sig
>>>     module T : sig  end
>>>     module C : sig type t = Make(T).t end
>>>     type t = Make(T).t
>>>   end
>>>
>>> # module B = struct
>>>   module C = struct
>>>     module T = struct end
>>>     include Make(T)
>>>   end
>>>   include C
>>> end
>>> ;;
>>> module B :
>>>   sig
>>>     module C : sig module T : sig  end type t = Make(T).t end
>>>     module T = C.T
>>>     type t = Make(T).t
>>>   end
>>>
>>>
>>> Note the important difference in the inferred signatures in both
>>> cases. Both modules have
>>>     type t = Make(T).t
>>> but, in the first case, this is the *same module T* that is mentioned
>>> in the signature of T, while in the second case, there are two
>>> different modules, C.T and T (the latter being generated by the
>>> "include", with an equation that it is equal to the former).
>>>
>>> The reasoning to check against your signature
>>>   sig
>>>     type t
>>>     module C : S with type t = t
>>>   end
>>> is thus more complicated in the second case: the type-checker would
>>> need to use the equation (T = C.T) to check that indeed C.t is equal
>>> to t.
>>>
>>> I think this is due to the rather contorted way you define C first in
>>> the implementations and include it later, while in the signature first
>>> define t and then C. Note that the following signature, which is
>>> morally equivalent, accepts both implementations (and thus all the
>>> functors in your file):
>>>   sig
>>>     module C : S
>>>     type t = C.t
>>>   end
>>>
>>>
>>> On Fri, Feb 13, 2015 at 10:40 PM, Carl Eastlund
>>> <ceastlund@janestreet.com> wrote:
>>>> This seems to be a compiler bug, but let me know if I've missed something.
>>>> The behavior I see is that Make_ok1 and Make_ok2 compile fine, but the very
>>>> similar functor Make_bad does not.  I get this compile error:
>>>>
>>>> ========================================
>>>>
>>>>       Error: Signature mismatch:
>>>>              Modules do not match:
>>>>                sig
>>>>                  module C : sig module T : sig  end type t = Make(T).t end
>>>>                  module T = C.T
>>>>                  type t = Make(T).t
>>>>                end
>>>>              is not included in
>>>>                sig type t module C : sig type t = t end end
>>>>              In module C:
>>>>              Modules do not match:
>>>>                sig module T : sig  end type t = Make(T).t end
>>>>              is not included in
>>>>                sig type t = C.t end
>>>>              In module C:
>>>>              Type declarations do not match:
>>>>                type t = Make(T).t
>>>>              is not included in
>>>>                type t = t
>>>>
>>>> ========================================
>>>>
>>>> And here is the code:
>>>>
>>>> ========================================
>>>>
>>>> module type S = sig type t end
>>>> module Make (M : sig end) : S = struct type t end
>>>>
>>>> module Make_ok1 (M : sig end) : sig
>>>>
>>>>   type t
>>>>   module A : S with type t = t
>>>>
>>>> end = struct
>>>>
>>>>   module A = struct
>>>>     include Make (struct end)
>>>>   end
>>>>   include A
>>>>
>>>> end
>>>>
>>>> module Make_ok2 (M : sig end) : sig
>>>>
>>>>   type t
>>>>   module B : S with type t = t
>>>>
>>>> end = struct
>>>>
>>>>   module T = struct end
>>>>   module B = struct
>>>>     include Make (T)
>>>>   end
>>>>   include B
>>>>
>>>> end
>>>>
>>>> module Make_bad (M : sig end) : sig
>>>>
>>>>   type t
>>>>   module C : S with type t = t
>>>>
>>>> end = struct
>>>>
>>>>   module C = struct
>>>>     module T = struct end
>>>>     include Make (T)
>>>>   end
>>>>   include C
>>>>
>>>> end
>>>>
>>>> ========================================
>>>>
>>>> --
>>>> Carl Eastlund
>>
>> --
>> Caml-list mailing list.  Subscription management and archives:
>> https://sympa.inria.fr/sympa/arc/caml-list
>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>> Bug reports: http://caml.inria.fr/bin/caml-bugs

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

* Re: [Caml-list] Weird type error involving 'include' and applicative functors
  2015-02-19 18:21       ` Milan Stanojević
@ 2015-02-19 18:23         ` Milan Stanojević
  0 siblings, 0 replies; 8+ messages in thread
From: Milan Stanojević @ 2015-02-19 18:23 UTC (permalink / raw)
  To: Leo White; +Cc: Gabriel Scherer, Carl Eastlund, caml users

Oh, it seems Carl already did it. I'll mark mine as duplicate.

On Thu, Feb 19, 2015 at 1:21 PM, Milan Stanojević <milanst@gmail.com> wrote:
> I submitted a bug report.
> http://caml.inria.fr/mantis/view.php?id=6788
>
>
> On Tue, Feb 17, 2015 at 4:40 PM, Milan Stanojević <milanst@gmail.com> wrote:
>> It seems that type checker does know that C.T and T are aliases since
>> this compiles
>>
>>   module C = struct
>>     module T = struct end
>>     include Make (T)
>>   end
>>   include C
>>
>>   let f (x : Make(Make(T)).t) : Make(Make(C.T)).t = x
>>
>> Somehow the fact that C.T = T is lost when checking against the signature.
>>
>>
>>
>>
>> On Mon, Feb 16, 2015 at 1:03 PM, Leo White <lpw25@cam.ac.uk> wrote:
>>> Gabriel gives an accurate accout of what is going on. To me, it looks
>>> like the type-checker should probably accept this, so I would submit it
>>> as a bug (I suspect a missing call to Env.normalize_path somewhere, but
>>> perhaps there is something more significant going on here).
>>>
>>> Regards,
>>>
>>> Leo
>>>
>>> Gabriel Scherer <gabriel.scherer@gmail.com> writes:
>>>
>>>> That is one of the dark corners of the module system.
>>>>
>>>> I don't know whether an ideal type-checker should accept your last
>>>> definition or not. It is non-intuitive that some are accepted and
>>>> others rejected; some things in the module system are non-intuitive
>>>> for good reasons, some others because of implementation limitations,
>>>> and it's not always clear to non-experts which is which).˙But I can
>>>> explain why the last definition is harder for the type-checker to
>>>> accept than the other.
>>>>
>>>> # module A = struct
>>>>   module T = struct end
>>>>   module C = struct
>>>>     include Make(T)
>>>>   end
>>>>   include C
>>>> end
>>>> ;;
>>>> module A :
>>>>   sig
>>>>     module T : sig  end
>>>>     module C : sig type t = Make(T).t end
>>>>     type t = Make(T).t
>>>>   end
>>>>
>>>> # module B = struct
>>>>   module C = struct
>>>>     module T = struct end
>>>>     include Make(T)
>>>>   end
>>>>   include C
>>>> end
>>>> ;;
>>>> module B :
>>>>   sig
>>>>     module C : sig module T : sig  end type t = Make(T).t end
>>>>     module T = C.T
>>>>     type t = Make(T).t
>>>>   end
>>>>
>>>>
>>>> Note the important difference in the inferred signatures in both
>>>> cases. Both modules have
>>>>     type t = Make(T).t
>>>> but, in the first case, this is the *same module T* that is mentioned
>>>> in the signature of T, while in the second case, there are two
>>>> different modules, C.T and T (the latter being generated by the
>>>> "include", with an equation that it is equal to the former).
>>>>
>>>> The reasoning to check against your signature
>>>>   sig
>>>>     type t
>>>>     module C : S with type t = t
>>>>   end
>>>> is thus more complicated in the second case: the type-checker would
>>>> need to use the equation (T = C.T) to check that indeed C.t is equal
>>>> to t.
>>>>
>>>> I think this is due to the rather contorted way you define C first in
>>>> the implementations and include it later, while in the signature first
>>>> define t and then C. Note that the following signature, which is
>>>> morally equivalent, accepts both implementations (and thus all the
>>>> functors in your file):
>>>>   sig
>>>>     module C : S
>>>>     type t = C.t
>>>>   end
>>>>
>>>>
>>>> On Fri, Feb 13, 2015 at 10:40 PM, Carl Eastlund
>>>> <ceastlund@janestreet.com> wrote:
>>>>> This seems to be a compiler bug, but let me know if I've missed something.
>>>>> The behavior I see is that Make_ok1 and Make_ok2 compile fine, but the very
>>>>> similar functor Make_bad does not.  I get this compile error:
>>>>>
>>>>> ========================================
>>>>>
>>>>>       Error: Signature mismatch:
>>>>>              Modules do not match:
>>>>>                sig
>>>>>                  module C : sig module T : sig  end type t = Make(T).t end
>>>>>                  module T = C.T
>>>>>                  type t = Make(T).t
>>>>>                end
>>>>>              is not included in
>>>>>                sig type t module C : sig type t = t end end
>>>>>              In module C:
>>>>>              Modules do not match:
>>>>>                sig module T : sig  end type t = Make(T).t end
>>>>>              is not included in
>>>>>                sig type t = C.t end
>>>>>              In module C:
>>>>>              Type declarations do not match:
>>>>>                type t = Make(T).t
>>>>>              is not included in
>>>>>                type t = t
>>>>>
>>>>> ========================================
>>>>>
>>>>> And here is the code:
>>>>>
>>>>> ========================================
>>>>>
>>>>> module type S = sig type t end
>>>>> module Make (M : sig end) : S = struct type t end
>>>>>
>>>>> module Make_ok1 (M : sig end) : sig
>>>>>
>>>>>   type t
>>>>>   module A : S with type t = t
>>>>>
>>>>> end = struct
>>>>>
>>>>>   module A = struct
>>>>>     include Make (struct end)
>>>>>   end
>>>>>   include A
>>>>>
>>>>> end
>>>>>
>>>>> module Make_ok2 (M : sig end) : sig
>>>>>
>>>>>   type t
>>>>>   module B : S with type t = t
>>>>>
>>>>> end = struct
>>>>>
>>>>>   module T = struct end
>>>>>   module B = struct
>>>>>     include Make (T)
>>>>>   end
>>>>>   include B
>>>>>
>>>>> end
>>>>>
>>>>> module Make_bad (M : sig end) : sig
>>>>>
>>>>>   type t
>>>>>   module C : S with type t = t
>>>>>
>>>>> end = struct
>>>>>
>>>>>   module C = struct
>>>>>     module T = struct end
>>>>>     include Make (T)
>>>>>   end
>>>>>   include C
>>>>>
>>>>> end
>>>>>
>>>>> ========================================
>>>>>
>>>>> --
>>>>> Carl Eastlund
>>>
>>> --
>>> Caml-list mailing list.  Subscription management and archives:
>>> https://sympa.inria.fr/sympa/arc/caml-list
>>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>>> Bug reports: http://caml.inria.fr/bin/caml-bugs

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

* Re: [Caml-list] Weird type error involving 'include' and applicative functors
  2015-02-15 10:26 ` Gabriel Scherer
  2015-02-16 18:03   ` Leo White
@ 2015-02-24  4:38   ` Jacques Garrigue
  2015-02-24  5:54     ` Jacques Garrigue
  1 sibling, 1 reply; 8+ messages in thread
From: Jacques Garrigue @ 2015-02-24  4:38 UTC (permalink / raw)
  To: Gabriel Scherer; +Cc: Carl Eastlund, OCaml Mailing List

On 2015/02/15 19:26, Gabriel Scherer wrote:
> 
> That is one of the dark corners of the module system.
[…]
> I think this is due to the rather contorted way you define C first in
> the implementations and include it later, while in the signature first
> define t and then C. Note that the following signature, which is
> morally equivalent, accepts both implementations (and thus all the
> functors in your file):
>  sig
>    module C : S
>    type t = C.t
>  end

This is indeed the gist of the problem. Matching against

    sig
      type t
      module C : S with type t = t
    end

introduces a kind of mutual recursion: C.t is defined as t in the enclosing
signature, but t is C.t in the internal one. As a result we get a kind of
double-vision problem. Namely, t inside the internal C is Make(T).t (with
T the one inside C), but in the enclosing signature, the t inside C
is Make(C.T).t. While logically the T inside C and C.T are the same module,
the typing rule in Leroy's paper do not say anything like that.

σ : {1,...,m} 􏰀→ {1,...,n} for all i ∈ {1,...,m}, E;D1;...;Dn ⊢ Dσ(i) <: Di′
---------------------------------------------------------------------------------------
          E ⊢ sig D1;…;Dn end <: sig D1′ ;...;Dm′ end

The definition in the premise must match without extra equations.
Here module aliases do not help.
What could help would be to strengthen the definitions in the premise, so
that T would be converted to C.T. But I don't know whether this is sound
or not, since this is not part of the current theory.

Jacques Garrigue


> On Fri, Feb 13, 2015 at 10:40 PM, Carl Eastlund
> <ceastlund@janestreet.com> wrote:
>> This seems to be a compiler bug, but let me know if I've missed something.
>> The behavior I see is that Make_ok1 and Make_ok2 compile fine, but the very
>> similar functor Make_bad does not.  I get this compile error:
>> 
>> ========================================
>> 
>>      Error: Signature mismatch:
>>             Modules do not match:
>>               sig
>>                 module C : sig module T : sig  end type t = Make(T).t end
>>                 module T = C.T
>>                 type t = Make(T).t
>>               end
>>             is not included in
>>               sig type t module C : sig type t = t end end
>>             In module C:
>>             Modules do not match:
>>               sig module T : sig  end type t = Make(T).t end
>>             is not included in
>>               sig type t = C.t end
>>             In module C:
>>             Type declarations do not match:
>>               type t = Make(T).t
>>             is not included in
>>               type t = t
>> 
>> ========================================
>> 
>> And here is the code:
>> 
>> ========================================
>> 
>> module type S = sig type t end
>> module Make (M : sig end) : S = struct type t end
>> 
>> module Make_ok1 (M : sig end) : sig
>> 
>>  type t
>>  module A : S with type t = t
>> 
>> end = struct
>> 
>>  module A = struct
>>    include Make (struct end)
>>  end
>>  include A
>> 
>> end
>> 
>> module Make_ok2 (M : sig end) : sig
>> 
>>  type t
>>  module B : S with type t = t
>> 
>> end = struct
>> 
>>  module T = struct end
>>  module B = struct
>>    include Make (T)
>>  end
>>  include B
>> 
>> end
>> 
>> module Make_bad (M : sig end) : sig
>> 
>>  type t
>>  module C : S with type t = t
>> 
>> end = struct
>> 
>>  module C = struct
>>    module T = struct end
>>    include Make (T)
>>  end
>>  include C
>> 
>> end
>> 
>> ========================================
>> 
>> --
>> Carl Eastlund




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

* Re: [Caml-list] Weird type error involving 'include' and applicative functors
  2015-02-24  4:38   ` Jacques Garrigue
@ 2015-02-24  5:54     ` Jacques Garrigue
  0 siblings, 0 replies; 8+ messages in thread
From: Jacques Garrigue @ 2015-02-24  5:54 UTC (permalink / raw)
  To: Gabriel Scherer; +Cc: Carl Eastlund, OCaml Mailing List

On 2015/02/24 13:38, Jacques Garrigue <garrigue@math.nagoya-u.ac.jp> wrote:

>  While logically the T inside C and C.T are the same module,
> the typing rule in Leroy's paper do not say anything like that.
> 
> σ : {1,...,m} 􏰀→ {1,...,n} for all i ∈ {1,...,m}, E;D1;...;Dn ⊢ Dσ(i) <: Di′
> ---------------------------------------------------------------------------------------
>          E ⊢ sig D1;…;Dn end <: sig D1′ ;...;Dm′ end
> 
> The definition in the premise must match without extra equations.
> Here module aliases do not help.
> What could help would be to strengthen the definitions in the premise, so
> that T would be converted to C.T. But I don't know whether this is sound
> or not, since this is not part of the current theory.

More precisely, OCaml actually does a bit more than this rule, as it
strengthens abstract types. However there is no such thing as strengthening
for module aliases, as this would require having both a signature and an
alias for the same module. Allowing that could help solve this problem, but
this is not fixing a bug, rather extending the theory.

Jacques Garrigue



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

end of thread, other threads:[~2015-02-24  5:54 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-13 21:40 [Caml-list] Weird type error involving 'include' and applicative functors Carl Eastlund
2015-02-15 10:26 ` Gabriel Scherer
2015-02-16 18:03   ` Leo White
2015-02-17 21:40     ` Milan Stanojević
2015-02-19 18:21       ` Milan Stanojević
2015-02-19 18:23         ` Milan Stanojević
2015-02-24  4:38   ` Jacques Garrigue
2015-02-24  5:54     ` Jacques Garrigue

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