4

I have a weird problem on my code, and I really don't know how to solve it: My code is the following:

module type tGraphe = sig
    type node
    type arc
    end;;

module One : tGraphe with type node=int and type arc=int = struct
    type noeud=int
    type arc=int
end;;

module Two : tGraphe with type node=int and type arc=Empty|Node of(int*int) = struct
    type node=int
    type arc=Empty|Node of(int*int)
end;;

Module One doesn't encounter any problem, but for the module Two, it is indicated that there is a Syntax Error for type arc. And if somebody can explain me how to use the types of the modules without "with", I'd be grateful. Already tried

module Two : tGraphe= struct
        type node=int
        type arc=Empty|Node of(int*int)
end;;
open Two;;
let z=Empty;;

but it doesn't work.

Alexis Comte
  • 81
  • 1
  • 6

2 Answers2

4

When you define

type foo = int
type bar = Leaf | Node of int * int

there is a fundamental difference between foo, which is a type synonym for a type that already existed (int), and bar that introduces a new type, introducing new constructors Leaf and Node, and is distinct from all the previous ones.

When you write

module M = struct
  type foo = int
  type bar = Leaf | Node of int * int
end

the type M.foo is equal to int, but the type M.bar is only equal to itself: it is new and has nothing existing to compare to (even a type with the exact same constructors would be considered different and incompatible).

It makes sense to publish, in a signature, the fact that M.foo = int, but not to say that M.bar = Leaf | ...: M.bar is only equal to itself, M.bar, and the signature refinement M with type bar = M.bar would not give you any information.

The problem in your code is that you insist on using an ascription to the signature tGraphe that uses abstract types. You gain nothing by writing jrouquie's code

type global_arc = Vide | Node of (int*int)

module Two : tGraphe with type noeud = int and type arc = global_arc = struct
  type noeud = int
  type arc = global_arc
end;;

instead of simply

module Two = struct
    type noeud = int
    type arc = Vide |Node of(int*int)
end

The construction M : S is not a check only. It will actively hide typing information from M. The construction S with type ... = ... is there to allow to hide a bit less than you would with S. But if you want to hide nothing at all, in your example, just don't use a signature ascription! Just write module M = struct ... end.

If you only use : S to check that you were not wrong, didn't make any mistake in fields names and stuff, you can use it on the side as a pure check:

module Two = struct ... end

let () = ignore (module Two : S) (* only a check! *)

SML has a distinction between "transparent" module annotations that only check compatibility, and "opaque" module annotations (generally called sealing), that enforce compatibility and hide type information. OCaml only has the opaque sealing ones, so you have to be careful not to over-use it.

PS: when asking a question on StackOverflow, it would be better if your code was written in english than in french.

gasche
  • 31,259
  • 3
  • 78
  • 100
  • Thanks for all thoses precisions, and sorry about my french code. I totally forgotten to verify if my code was containing some french words. – Alexis Comte Apr 16 '13 at 12:24
0

I'm not sure to understand what you want. The following code works, but I don't know if it fulfill your needs.

module type tGraphe = sig
  type noeud
  type arc
end;;

type global_arc = Vide | Node of (int*int)

module Two : tGraphe with type noeud = int and type arc = global_arc = struct
  type noeud = int
  type arc = global_arc
end;;

let z: Two.arc = Vide;;
jrouquie
  • 4,315
  • 4
  • 27
  • 43
  • Yes, it will fulfill all my requirements, except the fact that, if I can, I would prefer to have all the definitions in the module, so without any global type like this "global_arc". But if I can't do in a other way, I will conserve this method. Thanks :) – Alexis Comte Apr 16 '13 at 08:50
  • The problem is that if you define twice the same type, the OCaml compiler will interpret the two types as two different types (even if they have the same definition). To prevent this and ensure that the two types are the same, you must define it upfront as jrouquie suggests. – Thomash Apr 16 '13 at 09:44