OCaml repeating entire signature in implementation

Suppose I have a module A, with the following interface and implementation files:

(* a.mli *)
module type A_SIG =
sig
    val f: int -> int
    ...
end

(* a.ml *)
module A : A_SIG =
struct
    let f x = x + 1
    ...
end

Compiling a.mli followed by a.ml fails, with error Unbound module type A_SIG. Duplicating the entire signature in the implementation file fixes it.

Why is this the case? It seems that the following works in SML:

(* a.sig *)
signature A_SIG =
sig
    val f: int -> int
    ...
end

(* a.sml *)
structure A : A_SIG =
struct
   fun f x = x+1
   ...
end

I've seen this similar post, but its answer is unclear to me.

1 answer

  • answered 2018-07-11 07:18 tbrk

    The file a.ml is implicitly wrapped as the module A and the file a.mli is implicitly wrapped as the module type A.

    So the following works

    (* A.mli *)
    val f : int -> int
    
    (* A.ml *)
    let f x = x + 1
    

    And you would access f from another module as A.f.

    Or if you really want submodules you could write

    (* a.mli *)
    module type A_SIG =
    sig
        val f: int -> int
    end
    
    module A : A_SIG
    
    (* a.ml *)
    module type A_SIG =
    sig
        val f: int -> int
    end
    
    module A : A_SIG =
    struct
        let f x = x + 1
    end
    

    And you would access f from another module as A.A.f and the module A would also contain the signature A_SIG, in addition to the (sub)module A.

    Implementations of Standard ML do not normally implicitly wrap the contents of a file as a module.

    For completeness, note that OCaml has a feature to "generate" a module type from a module:

    (* a.mli *)
    module type A_SIG =
    sig
        val f: int -> int
    end
    
    module A : A_SIG
    
    (* a.ml *)
    module A =
    struct
        let f x = x + 1
    end
    
    module type A_SIG = module type of A