4
votes

I confused with module type in Ocaml.

I wondered that in which situation we should use module type?

I usually use module sig in .mli to expose some detail, and put corresponding implementation module struct in .ml.

For example:

.mli

module A:
 sig
   type t = T of string
 end

.ml

module A =
 struct
   type t = T of string
 end

For this reason, I think Ocaml's module like .h and .c file in C.

I know that module type can declare a interface, but the interface were not as same as Java's interface.

Like an example in book:

open Core.Std

 module type ID = sig
  type t
   val of_string : string -> t
  val to_string : t -> string
 end

  module String_id = struct
   type t = string
    let of_string x = x
    let to_string x = x
  end

  module Username : ID = String_id
  module Hostname : ID = String_id

  type session_info = { user: Username.t;
                  host: Hostname.t;
                  when_started: Time.t;
                }

  let sessions_have_same_user s1 s2 =
       s1.user = s2.host

The preceding code has a bug: it compares the username in one session to the host in the other session, when it should be comparing the usernames in both cases.

It seems that module type can not provide a new common super type for it's implementation.

What the real application for module type??

3

3 Answers

6
votes

Here, the module type is used to hide the type t to the user of the module.

When one makes use of Username.t or Hostname.t one can not rely on those types being strings, integers, or any specific type. The module type makes them opaque, as if they were not part of the interface of the module, but only an implementation detail, that the module writer is going to change in the future.

Basically, the user of the module can only act on type t through the module functions.

The compiler checks that the user code does not make any assumptions about what these types t actually are, so that in the future the module writer can change them without breaking the user code.

3
votes

As it already mentioned, here module type is used to achieve more abstract vision of type t. When you define Username and Hostname as two separate modules its means that logically they must be different and that signature of this modules it's the only possible way to work with them.

But you're wrong when you say:

It seems that module type can not provide a new common super type for it's implementation.

Actually you can precise that Username.t and Hostname.t are the same types.

module Username = (String_id : ID with type t = String_id.t)
module Hostname = (String_id : ID with type t = String_id.t)

Username.to_string (Hostname.of_string "hi")

Here it's useless but sometimes it's really helpful.

0
votes

module types are intimately related to functors. Read the module system chapter.

The argument of a functor has some module type, and so has its result.

Functors are used a lot, and most standard containers (e.g. Set-s or Map-s) are functors.

If you develop your generic containers, you surely will want functors and module types.

(so functors and module types are as useful in Ocaml than templates are useful in C++)