OCAML first class modules signature inference

419 Views Asked by At

1) Suppose there is a module

module Int_Sig_1 =
struct
let x = 1
end
;;

2) and an explicit signature of this module

module type INT_SIG =
sig
val x:int
end
;;

3) and i create a first-class module based on the above module and module type

let int_sig_1 = (module Int_Sig_1:INT_SIG)

4) Now i create another module with no explicit signature but same inferred signature as above

module Int_Sig_2 =
struct
let x =2
end
;;

5) As written in Chapter 10 of the book Real World OCAML "The module type doesn't need to be part of the construction of a first-class module if it can be inferred", i try to create a second first class module using the above module but with no explicit module type

let a2 = (module Int_Sig_2);;

I get the following error

Error: The signature for this packaged module couldn't be inferred.

6) then i try to do the same as above in 5, but this time I put the first class module with no module type being create as an element of a list, where the head of the list is a first class module that was created out of an explicit signature in 3 above.

let int_sig= [int_sig_1;(module Int_Sig_2)];;
val int_sig : (module INT_SIG) list = [<module>; <module>] ;;

My question is why 5 above gives me an error and 6 does not fail ?

1

There are 1 best solutions below

6
octachron On

The problem with (5) is that in general, there are multiple module types that could be infered. In your example, there is at least two valid module types which could be used to pack Int_Sig_2:

 module type empty = sig end
 module type with_x = sig val x:int end

In other words, both

 let a2 = (module Int_Sig_2: empty)
 let a2_bis = (module Int_Sig_2:with_x)

are valid. Consequently, the type checker will not try to infer a module type in this situation.

Contrarily, in your example (6), the type of the list is determined by its first element, whose type is (module INT_SIG_2), therefore the type-checker can use this information to infer that the expected type for the second element of the list is (module INT_SIG_2). Nevertheless, reversing the two elements yields a type error. In other words, this is fine:

 [(module struct let x = 2 end: with_x); (module struct let x = 1 end)]

however, the reverse yields

[(module struct let x=2 end); (module struct let x = 3 end:with_x)];;
Error: The signature for this packaged module couldn't be inferred. 

This is due to the fact that the type-checker has a left-to-right bias and types first the first element of the list first.