ocaml

OCaml `Map.Make` input module


I am following the example here.

module IntPairs =
struct
  type t = int * int
  let compare (x0,y0) (x1,y1) =
    match Stdlib.compare x0 x1 with
    | 0 -> Stdlib.compare y0 y1
    | c -> c
end

module PairsMap = Map.Make(IntPairs)

let m = PairsMap.(
  empty 
  |> add (0,1) "hello" 
  |> add (1,0) "world"
)

My question is, why the code doesn't compile when I add : Map.OrderedType to the module IntPairs definition? Like this:

module IntPairs : Map.OrderedType =
struct
  type t = int * int
  let compare (x0,y0) (x1,y1) =
    match Stdlib.compare x0 x1 with
    | 0 -> Stdlib.compare y0 y1
    | c -> c
end

module PairsMap = Map.Make(IntPairs)

let m = PairsMap.(
  empty 
  |> add (0,1) "hello" 
  |> add (1,0) "world"
)

Error message:

64 | let m = PairsMap.(empty |> add (0, 1) "hello" |> add (1, 0) "world")
                                    ^^^^^^
Error: This expression has type 'a * 'b
       but an expression was expected of type 
       key

Isn't IntPairs expected to implement the module type Map.OrderedType?


Solution

  • When you specify the type Map.OrderedType you make the type of the key abstract because that module signature doesn't tell us anything about type t. Instead, expose the type of t explicitly and you'll find your code works.

    module IntPairs : Map.OrderedType with type t = int * int =
    struct
      type t = int * int
      let compare (x0,y0) (x1,y1) =
        match Stdlib.compare x0 x1 with
        | 0 -> Stdlib.compare y0 y1
        | c -> c
    end
    

    Or taking advantage of the fact that Stdlib.compare already works this way for tuples of ints.

    module IntPairs : Map.OrderedType with type t = int * int =
    struct
      type t = int * int
      let compare = Stdlib.compare
    end
    

    It may disambiguate the syntax here to add a set of parentheses.

    module IntPairs : (Map.OrderedType with type t = int * int) =
    ...
    

    As noted in comments, the other option is simply not to restrict the type of IntPairs at all.

    module IntPairs =
    struct
      type t = int * int
      let compare = Stdlib.compare
    end
    
    module PairsMap = Map.Make (IntPairs)