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
t
an abstract type, which can only be consumed by theto_string
function and never been produced. In other words, a module of typePrintable
is 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
FromToString
case, this is:You can see that the inferred module type of the result
that it is quite similar to
Printable
except that now the typet
is equal to the typet
of the argument moduleS
.Thus, it is possible to reuse
Printable
to write the full module type of the result by adding a type equality with awith
constraint:The same issue appears for IntToString and can be fixed in a similar way:
Then the compiler error is gone: