Oleg
Oleg

Reputation: 1559

Confusion about signature of a module in Ocaml

Is there any difference between these two ?

I don't know which of them should I put in my .mli file

module Comparable : sig 
    type t
    val compare : t -> t-> int
end

module type Comparable = sig
    type t
    val compare : t -> t-> int
end

In real world ocaml book, the authors say that the words interface, signature, module type can be used interchangeably.

PS:I would gladly change the question title to a better suited one, any proposals ?

Upvotes: 1

Views: 643

Answers (4)

kne
kne

Reputation: 1418

module type Comparable = sig
  type t
  val compare : t -> t-> int
end

defines a module type. Inside an interface (e.g. a .mli file), it is a promise that the implementation (the .ml) contains the same module type definition.

module Comparable : sig 
    type t
    val compare : t -> t-> int
end

in an interface is a promise to provide a module of that same type. It would be equivalent to

module Comparable : Comparable

(assuming the module type is indeed defined). It states that the corresponding .ml contains a submodule named Comparable.

Which of the two you should put in you .mli depends on what promises you want to make. Both have their uses.

Module type definitions are commonly found in interfaces if they are needed as arguments to functors. Indeed your module type Comparable is equal to Map.OrderedType, the type of the argument of the functor Map.Make.

One use case of submodules as above is to provide something that can be used as an argument to a functor. For example a .mli could look like this:

type stuff = ...
val fancy : ... (* some operations on stuff *)

module Comparable : Comparable with type t=stuff

In this form it would make the type stuff usable as the key type of a map.

That said, if your example is the complete real world example, then I suspect you want the module type definition, not the submodule: The submodule would not be very useful; you have no operation to construct anything of type t.

Upvotes: 4

octachron
octachron

Reputation: 18912

Your first code fragment defines a module with a specific signature , the second one defines directly a signature not a module. To understand the difference, your code example may be rewriten to

module type COMPARABLE = sig 
   type t
   val compare : t -> t-> int
end

module Comparable: COMPARABLE

Upvotes: 2

Pierre G.
Pierre G.

Reputation: 4441

.mli file allows to constraint a .ml file, see the example below :

   /* foo.ml */
   let foo1 x y = x + y
   let foo  = foo1

   /* foo.mli */
   val foo : int -> int -> int

   /* main.ml */
   open Foo
   let r = foo 4 5
   /* let r = foo1 4 5 ;; */

ocamlbuild main.native will compile only when using foo and will fail to compiler with foo1.

Now, when you define a module, you can either hide some declaration when defining this module :

   module Comparable : sig 
   /* the exposed interface */
   end = struct 
   /* the computation */ 
   end

Or, define a type for a module :

   module type Comparable = sig 
   /* the exposed interface */
   end

You will be able to use that type later in your code to constraint some module. With the example given above (!! delete the .mli file !!)

   /* foo.ml */
   let foo1 x y = x + y
   let foo  = foo1

   /* main.ml */
   module type T1 = sig 
   val foo : int -> int -> int
   end

   module F1 : T1 = Foo
   let r = Foo.foo1 4 5 
   let r = F1.foo1 4 5 /* will fail because hiden by type T1 */

Upvotes: 1

Jeffrey Scofield
Jeffrey Scofield

Reputation: 66823

Say your file is named m.mli. The first definition is what you use if your corresponding m.ml file has a module Comparable in it. The second is what you use to declare a module type (just the type of a module, not a module). In the first case, there is an actual compare that can be called as M.Comparable.compare. In the second case there's no compare function, just a type declaration.

It's not possible to know which is correct for you. They both make sense.

Upvotes: 1

Related Questions