Map with Janestreet Core_kernel

I'm doing Real World Ocaml, with Ocaml 4.06, emacs/merlin. Please see following code snippet. I have two questions:

open Core_kernel

let () =
  let digit_alist = [ 0, "zero"; 1, "one"; 2, "two"  ; 3, "three"; 4, "four";
                      5, "five"; 6, "six"; 7, "seven"; 8, "eight"; 9, "nine" ] in
  let _ = Map.of_alist_exn digit_alist ~comparator:Int.comparator in
  ()

When evaluating from merlin, it shows two errors. It looks like that Map.of_alist_exn does not accept labeled argument ~comparator.:

This expression has type (int * string) list
       but an expression was expected of type
         ('a, 'b) Core_kernel.Map.comparator =
           (module Core_kernel__.Comparator.S with type comparator_witness = 'b and type t = 'a)

The function applied to this argument has type
         ('a * 'b) Core_kernel__.Import.list -> ('a, 'b, 'c) Base__Map.t
This argument cannot be applied with label ~comparator

Q1) Has the function type of Map.of_alist_exn changed?

And I think that the function type has been changed. So I changed the source code like this:

open Core_kernel

let () =
  let digit_alist = [ 0, "zero"; 1, "one"; 2, "two"  ; 3, "three"; 4, "four";
                      5, "five"; 6, "six"; 7, "seven"; 8, "eight"; 9, "nine" ] in
  let _ = Map.of_alist_exn Int.comparator digit_alist in
  ()

At this time, merlin complains like this:

This expression has type
         (Core_kernel.Int.t, Core_kernel.Int.comparator_witness)
         Core_kernel__.Comparator.comparator =
           (Core_kernel.Int.t, Core_kernel.Int.comparator_witness)
           Base__Comparator.t
       but an expression was expected of type
         ('a, 'b) Core_kernel.Map.comparator =
           (module Core_kernel__.Comparator.S with type comparator_witness = 'b and type t = 'a)

I expect Int.comparator will do the role of valid comparator, but ocaml regard it as invalid.

Q2) What should I give it for comparator?

@A struggling noob

1 answer

  • answered 2018-02-13 01:21 Bikal Lem

    Looking at the definition of comparator, we can see it defined as following,

    type ('k, 'cmp) comparator = (module Comparator.S with type comparator_witness = 'cmp and type t = 'k)
    

    In ocaml, modules can be used as first class values. One interesting consequence of that feature is that modules can now be defined as types and be passed/used as function parameters/arguments. Janestreet core_kernel and/or base makes heavy use of first class modules as you have found out. Map.comparator is one such use case.

    Comparator.S is defined as follows:

    module type Core_kernel.Comparator.S
    type t
    type comparator_witness
    val comparator : (t, comparator_witness) comparator
    

    If you look at the module signature for module Int - #show Core_kernel.Int in utop, then we can see that it defines the type and the functions as prescribed in Core_kernel.Comparator.S module type.

    Thus, Map.of_alist_exn accepts (module Int) as a valid parameter. (module Int) is the ocaml syntax which denotes that the value is being passed as a first class module.

    Refs:

    1. https://ocaml.janestreet.com/ocaml-core/latest/doc/core_kernel/Core_kernel/Map/#type-comparator
    2. https://ocaml.janestreet.com/ocaml-core/latest/doc/core_kernel/Core_kernel/Comparator/module-type-S/