I am new to OCaml and I am trying use functors. When I use the module type annotations with the functors, this results in a compile time error in my code.
When I remove the : Printable (from the module FromToString line) and the : ToString (from the module IntToString line) annotations, the following program compiles without error:
module type ToString =
sig
type t
val to_string: t -> string
end
module type Printable =
sig
type t
val print: t -> unit
end
module FromToString (S:ToString) : Printable =
struct
type t = S.t
let print a = print_string ( S.to_string a)
end
module IntToString : ToString =
struct
type t = int
let to_string = string_of_int
end
module PrintableInt = FromToString(IntToString)
let () = PrintableInt.print 3
However, when I add these annotations (as shown in the code) the compiler gives the following error:
File "Functor.ml", line 26, characters 28-29:
Error: This expression has type int but an expression was expected of type
PrintableInt.t = FromToString(IntToString).t
How can I use these annotations without causing a compile error?
The root issue is that your signature constraints make the resulting module far too opaque. When you constrain your functor result:
you are making the type
tan abstract type, which can only be consumed by theto_stringfunction and never been produced. In other words, a module of typePrintableis unusable by itself.When starting with functor, it is very often useful to look at the module type inferred by the compiler for the resulting module. In the
FromToStringcase, this is:You can see that the inferred module type of the result
that it is quite similar to
Printableexcept that now the typetis equal to the typetof the argument moduleS.Thus, it is possible to reuse
Printableto write the full module type of the result by adding a type equality with awithconstraint:The same issue appears for IntToString and can be fixed in a similar way:
Then the compiler error is gone: