1

I am new to OCaml and I am struggling a bit with understanding how module types work.

module type I = sig
  type t
end

module EQ (M : I) = struct
  let equal (x : M.t) (y : M.t) = x = y
end

(* Explicitly type declaration *)
module A : I = struct
  type t = string
end

module EStr1 = EQ (A)

(* Error: This expression has type string but an expression was expected of type
         A.t *)
let _ = EStr1.equal "1" "0" |> string_of_bool |> print_endline

(* No type declaration *)
module B = struct
  type t = string
end

module EStr2 = EQ (B)

(* OK. Outputs false *)
let _ = EStr2.equal "1" "0" |> string_of_bool |> print_endline

In the code above i declared module type I, module A with explicit module type declaration and module B without module type declaration. EQ is functor that receives module of type I and returns module with equal method.

Example with module A result in compiling error, while another works as I expected. What is semantic difference between this examples?

1 Answer 1

1

The output from the toplevel interpreter is instructive.

# module type I = sig
  type t
end

module EQ (M : I) = struct
  let equal (x : M.t) (y : M.t) = x = y
end

(* Explicitly type declaration *)
module A : I = struct
  type t = string
end

module EStr1 = EQ (A);;
module type I = sig type t end
module EQ : functor (M : I) -> sig val equal : M.t -> M.t -> bool end
module A : I
module EStr1 : sig val equal : A.t -> A.t -> bool end

Note the signature for the EStr1 module. EStr1.equal has type A.t -> A.t -> bool. Not type string -> string -> bool.

Applying the I signature to A has restricted us from knowing what A.t is. It is an abstract type. You haven't done that with B, so EStr2.equal does have type string -> string -> bool.

You can also explicitly expose this type information.

# module A : I with type t = string = struct
  type t = string
end;;
module A : sig type t = string end
# module C = EQ (A);;
module C : sig val equal : string -> string -> bool end

Once you understand how abstract types work, they are very useful.

Sign up to request clarification or add additional context in comments.

4 Comments

I got it now, thanks.
But it seems that only usecase of applying signature to module is to ask compiler to check that module satisfies signature, because applying signature is only give restrictions, am i missing something?
@Kon: I think the main thing you're missing is just that restrictions can be good. We want to help the compiler detect/prevent bugs; and just because two types are both implemented as string, that doesn't mean that it's meaningful/useful/correct to use them interchangeably.
Yeah, I understand that restrictions are good - in the end type system is about clever restrictions. Just wanted to ensure that i understanded correctly, thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.