typesocamlsignaturefunctor

What causes this type mismatch when applying a functor?


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.


Solution

  • 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