Search code examples
ocaml

OCaml Type Mismatch Error with Functor-Based Dictionary Insertion


I'm working on an OCaml project where I've defined a functor-based dictionary using modules and functors. I've encountered a type mismatch error when trying to insert elements into the dictionary. I've used a functor MakeListDictionary to create a dictionary module ListDict with integer keys and values.

(* The code is about a List based dictionary, and when use insert function, it throws an error. *)
module type Formattable = sig
  type t
  val format : Format.formatter -> t -> unit
end

module type Comparable = sig
  type t
  val compare : t -> t -> [ `EQ | `GT | `LT ]
  include Formattable with type t := t
end

module IntComparable : Comparable = struct
  type t = int
  let compare x y = if x < y then `LT else if x > y then `GT else `EQ
  let format fmt t = Format.fprintf fmt "%d" t
end

module IntFormattable : Formattable = struct
  type t = int
  let format fmt t = Format.fprintf fmt "%d" t
end

let dict = ListDict.empty;;
ListDict.insert 1 1 dict;;

When I try to insert a key-value pair into the dictionary using ListDict.insert 1 1 dict, I receive the following error message:

Error: This expression has type int but an expression was expected of type ListDict.key

I'm confused because ListDict.key is an alias for IntComparable.t, which in turn is just an alias for int. I expected that passing integers directly to the insert function would work. Could someone explain why this type mismatch error is occurring and how to resolve it? Any insights or suggestions would be greatly appreciated.

Could someone explain why this type mismatch error is occurring and how to resolve it? Any insights or suggestions would be greatly appreciated.


Solution

  • The Comparable and Formattable module types say nothing about the nature of type t. By applying the Comparable and Formattable module types to IntComparable and IntFormattable you have made their t types abstract. You need to explicitly expose those types if you want to know anything about them outside of the module.

    module IntComparable : Comparable with type t = int = struct
      type t = int
      let compare x y = 
        if x < y then `LT 
        else if x > y then `GT 
        else `EQ
      let format fmt t = Format.fprintf fmt "%d" t
    end
    
    module IntFormattable : Formattable with type t = int = struct
      type t = int
      let format fmt t = Format.fprintf fmt "%d" t
    end
    

    Now:

    # ListDict.insert 1 1 dict;;
    - : (int * int) list = [(1, 1)]
    

    Alternatively, let structural typing of modules do its thing and elide the module type signature constraints so that the t types are not abstract.

    module IntComparable = struct
      type t = int
      let compare x y = 
        if x < y then `LT 
        else if x > y then `GT 
        else `EQ
      let format fmt t = Format.fprintf fmt "%d" t
    end
    
    module IntFormattable = struct
      type t = int
      let format fmt t = Format.fprintf fmt "%d" t
    end