caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Re: [Caml-list] types not equal when I expect them to be
       [not found] <fa.O3xm0idbEURic/azoi8VH23mQEw@ifi.uio.no>
@ 2012-03-07  8:02 ` Radu Grigore
  0 siblings, 0 replies; 3+ messages in thread
From: Radu Grigore @ 2012-03-07  8:02 UTC (permalink / raw)
  To: fa.caml; +Cc: Caml List

On Thursday, March 1, 2012 4:39:35 PM UTC, Ashish Agarwal wrote:
> But I don't understand why. Can anyone explain the main points. Thank you.

See the non-bug
  http://caml.inria.fr/mantis/view.php?id=3476

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

* Re: [Caml-list] types not equal when I expect them to be
  2012-03-01 16:38 Ashish Agarwal
@ 2012-03-01 22:18 ` Gabriel Scherer
  0 siblings, 0 replies; 3+ messages in thread
From: Gabriel Scherer @ 2012-03-01 22:18 UTC (permalink / raw)
  To: Ashish Agarwal; +Cc: Caml List

Note that Bar is actually unnecessary. The following code exhibit the
exact same behavior:

  module Foo = struct
    module St = struct type t = string let compare = compare end
    module Map (* : Map.S with type key = St.t *)
      = Map.Make(St)
    (* module Map = Map.Make(struct type t = string let compare =
compare end) *)
  end

  module Pack = struct
    module Foo = Foo
  end

  let x : int Foo.Map.t = Pack.Foo.Map.empty

The important point is the interface of Map.Make when looked through
the environment (for example when rebound by `module F = Map.Make`,
then compiled with `ocamlc -i`):

  functor (Ord : Map.OrderedType) ->
    sig
      type key = Ord.t
      type 'a t = 'a Map.Make(Ord).t
      ...
    end

Note the `'a t = 'a Map.Make(Ord).t` part: this is the result of
a so-called "strenghening" operation, where the abstract types `t` in
the signature of the module `M` are noted to be equal to `M.t`; this
allows `N` to remain type-compatible with `M` when writing `module N =
M`.

Now the result of this strenghtening operation in your case is that
your module Map defined in Foo has in its signature:

  type 'a t = 'a Map.Make(Foo.St).t

The sorrow and non-intuitive point is that, after rebinding in Pack,
Pack.Foo gets the following signature:

  type 'a t = 'a Map.Make(Pack.Foo.St).t

Those two type are not path-compatible because `Pack.Foo.St` is not
a path syntactically equal to `Foo.St` -- I'm not sure why the
type-checker couldn't check path equality upto known module aliasing,
however.

Now, why your fixes work:

1. by adding the `: Map.S with type key = ...` signature to your
   Foo.Map module, you seal the module under the Map.S signature which
   has its type `'a t` *abstract*. This cancels the effects of
   strenghtening in the definition of `Foo.Map`. Now, in the
   definition of Pack, aliasing `module Foo = Foo` re-apply
   strenghtening, and you get a `Pack.Foo` module with `type 'a t =
   Foo.Map.t`, so those two are compatible.

2. by applying `struct type t = String let compare = compare` directly
   instead of naming it `Foo.St`, you apply a module that is not
   itself a path, so the typing rules change and you get `'a
   Foo.Map.t` abstract as in the first case.

3. You could also define `St` out of `Foo`, so that types in both Foo
   and Pack.Foo have `type 'a t = Map.Make(St).t`. You are surely
   aware that could similarly use stdlib's `String` directly which
   provides a `compare` operation.

I believe this explains the observed behaviour of the type-checker --
the experts will surely correct if I made technical mistakes. I'm not
sure however whether this behavior is expected (or could be considered
slightly buggy), or if it is imposed by theoretical restrictions or
implementation considerations.

On Thu, Mar 1, 2012 at 5:38 PM, Ashish Agarwal <agarwal1975@gmail.com> wrote:
> The following code fails to compile:
>
> ----- a.ml ----
> module Foo = struct
>   module St = struct type t = string let compare = compare end
>
>   module Map (* : Map.S with type key = St.t *)
>     = Map.Make(St)
>
>   (* module Map = Map.Make(struct type t = string let compare = compare end)
> *)
> end
>
> module Bar = struct
>   type t = int Foo.Map.t
> end
>
> module Pack = struct
>   module Foo = Foo
>   module Bar = Bar
> end
>
> open Pack
> let x : Bar.t = Foo.Map.empty
> ----
>
> $ ocamlc -c foo.ml
> File "foo.ml", line 20, characters 16-29: (* refers to Foo.Map.empty on last
> line *)
> Error: This expression has type
>          'a Pack.Foo.Map.t = 'a Map.Make(Pack.Foo.St).t
>        but an expression was expected of type
>          Pack.Bar.t = int Map.Make(Foo.St).t
>
>
> So Pack.Foo and Foo are not compatible. By trial and error, I found two ways
> to resolve the problem:
>
> 1) Provide an explicit signature for Foo.Map (uncomment the provided
> signature), or
> 2) Inline the structure passed to Map.Make (comment out first definition of
> Foo.Map and uncomment the second one)
>
> But I don't understand why. Can anyone explain the main points. Thank you.
>


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

* [Caml-list] types not equal when I expect them to be
@ 2012-03-01 16:38 Ashish Agarwal
  2012-03-01 22:18 ` Gabriel Scherer
  0 siblings, 1 reply; 3+ messages in thread
From: Ashish Agarwal @ 2012-03-01 16:38 UTC (permalink / raw)
  To: Caml List

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

The following code fails to compile:

----- a.ml ----
module Foo = struct
  module St = struct type t = string let compare = compare end

  module Map (* : Map.S with type key = St.t *)
    = Map.Make(St)

  (* module Map = Map.Make(struct type t = string let compare = compare
end) *)
end

module Bar = struct
  type t = int Foo.Map.t
end

module Pack = struct
  module Foo = Foo
  module Bar = Bar
end

open Pack
let x : Bar.t = Foo.Map.empty
----

$ ocamlc -c foo.ml
File "foo.ml", line 20, characters 16-29: (* refers to Foo.Map.empty on
last line *)
Error: This expression has type
         'a Pack.Foo.Map.t = 'a Map.Make(Pack.Foo.St).t
       but an expression was expected of type
         Pack.Bar.t = int Map.Make(Foo.St).t


So Pack.Foo and Foo are not compatible. By trial and error, I found two
ways to resolve the problem:

1) Provide an explicit signature for Foo.Map (uncomment the provided
signature), or
2) Inline the structure passed to Map.Make (comment out first definition of
Foo.Map and uncomment the second one)

But I don't understand why. Can anyone explain the main points. Thank you.

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

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

end of thread, other threads:[~2012-03-07  8:02 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <fa.O3xm0idbEURic/azoi8VH23mQEw@ifi.uio.no>
2012-03-07  8:02 ` [Caml-list] types not equal when I expect them to be Radu Grigore
2012-03-01 16:38 Ashish Agarwal
2012-03-01 22:18 ` Gabriel Scherer

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