I have the following files:
SetMaker.mli
module type Element = sig
type t
val create : 'a -> t
val compare : t -> t -> int
val to_string : t -> string
end
module type Set = sig
type t
val empty : unit -> t
end
module Make (M : Element) : Set with type t = (M.t list)
SetMaker.ml
module type Element = sig
type t
val create : 'a -> t
val compare : t -> t -> int
val to_string : t -> string
end
module type Set = sig
type t
val empty : unit -> t
end
module Make (M:Element) = struct
type t = M.t list
let empty () = []
end
main.ml
open Mylib
module IntEl : SetMaker.Element with type t = int = struct
type t = int
let create (x:int) : t = x
let compare x y =
if x < y then -1
else if x = y then 0
else 1
let to_string = string_of_int
end
;;
I think some of that is possibly more verbose than it has to be but I just tried throwing around extra declarations just to see if it wouldn't fix things or perhaps give more information in the error message. In fact, in a related question (OCaml Type Mismatch Error with Functor-Based Dictionary Insertion) putting an extra type declaration solved that issue but doesn't seem to solve it here.
When I try to compile I get the error
Error: Signature mismatch:
...
Values do not match:
val create : t -> t
is not included in
val create : 'a -> t
The type t -> t is not compatible with the type 'a -> t
Type t is not compatible with type 'a
File "lib/SetMaker.mli", line 3, characters 2-22: Expected declaration
File "bin/main.ml", line 5, characters 6-12: Actual declaration
I'm quite confused by that because I thought 'a
was supposed to be a type variable which would be compatible with any type used consistently. So I would think 'a
could be of type t
whatever that type is.
As a specification, the function type 'a -> t
is stating that the function accepts arguments of any type 'a
and returns a t
.
The only values of this type are functions that ignore the first argument and can be rewritten as
let f _ = g ()
for some function g
.
For instance:
module M: sig
val f : 'a -> int
val f': 'a -> int
end = struct
let f _ = 0
let r = ref 2
let f' _ = incr r; !r
end
At a higher-level, a Set
module probably doesn't need to know how to create new elements, thus it is probably simpler to remove the underspecified function create
from the Element
module type.
module type Element = sig
type t
val compare : t -> t -> int
val to_string : t -> string
end