# Map.Make with polymorphic variant

**URL:** <https://discuss.ocaml.org/t/map-make-with-polymorphic-variant/15267>\
**Category:** Learning\
**Tags:** map\
**Created:** [September 10, 2024, 2:11pm UTC](https://discuss.ocaml.org/t/map-make-with-polymorphic-variant/15267 "2024-09-10T14:11:08Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![frederic-lang](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/frederic-lang/32/6678_2.png) [@frederic-lang](https://discuss.ocaml.org/u/frederic-lang)\
**Post date:** [September 10, 2024, 2:11pm UTC](https://discuss.ocaml.org/t/map-make-with-polymorphic-variant/15267/1 "2024-09-10T14:11:08Z")

</div>

Is there a way to instantiate the Map.Make functor with polymorphic variant ?  
Without writing by hand a module like

```auto
module Keys = struct
   type t= `Foo | `Bar
   let compare a b = match a, b with
      | `Foo, `Bar -> 1
      | `Foo, `Foo -> 0
      | `Bar, `Bar -> 0
      | `Bar, `Foo -> -1
end
module KeysMap = Map.Make(Keys)

```

the compare function is heavy, is there to way to make better ?

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [September 10, 2024, 2:50pm UTC](https://discuss.ocaml.org/t/map-make-with-polymorphic-variant/15267/2 "2024-09-10T14:50:06Z")

</div>

If you just need _any_ comparison function, you can use `Stdlib.compare`.

Cheers,  
Nicolas

---

<div class="post-metadata">

**Author:** ![frederic-lang](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/frederic-lang/32/6678_2.png) [@frederic-lang](https://discuss.ocaml.org/u/frederic-lang)\
**Post date:** [September 11, 2024, 9:56am UTC](https://discuss.ocaml.org/t/map-make-with-polymorphic-variant/15267/3 "2024-09-11T09:56:47Z")

</div>

Thank you !  
This is exactly what I was looking for

---

<div class="post-metadata">

**Author:** ![xvw](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/xvw/32/2041_2.png) [@xvw](https://discuss.ocaml.org/u/xvw)\
**Post date:** [September 11, 2024, 12:12pm UTC](https://discuss.ocaml.org/t/map-make-with-polymorphic-variant/15267/4 "2024-09-11T12:12:37Z")

</div>

Polymorphic comparison is [considered harmful](https://blog.janestreet.com/the-perils-of-polymorphic-compare/) but in that case, yes it works.  
Another trade-off will be given a function `[`Foo | `Bar] -> int` :

```ocaml
let to_int = function 
  | `Bar -> 0 
  | `Foo -> 1

```

And after that you can relay on `Int.compare` :

```ocaml
module Keys_map = Map.Make (struct 
  type t = [`Foo | `Bar]
  let compare a b = Int.compare (to_int a) (to_int b)
end)

```

---

<div class="post-metadata">

**Author:** ![sim642](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/sim642/32/3597_2.png) [@sim642](https://discuss.ocaml.org/u/sim642)\
**Post date:** [September 12, 2024, 6:38am UTC](https://discuss.ocaml.org/t/map-make-with-polymorphic-variant/15267/5 "2024-09-12T06:38:00Z")

</div>

Most of those harmful points don’t really apply here for such a simple type though.  
Sure, using `Stdlib.compare` blindly is a problem, but in this case structural comparison is exactly the goal (and it’s very simple structure).

The good way to use it here is to monomorphize it:

```ocaml
let compare (a: t) (b: t) = Stdlib.compare a b

```

Now the compiler can produce very efficient code that doesn’t require calling the generic `caml_compare` function from the runtime. This can be quickly seen with Godbolt: [Compiler Explorer](https://godbolt.org/z/bx9fvEcGa) (`compare3` is longer than the red highlighting seems to suggest).

An alternative approach which is convenient but less error-prone is to use a PPX such as: [GitHub - ocaml-ppx/ppx\_deriving: Type-driven code generation for OCaml](https://github.com/ocaml-ppx/ppx_deriving).

---

<div class="post-metadata">

**Author:** ![dra27](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dra27/32/5294_2.png) [@dra27](https://discuss.ocaml.org/u/dra27)\
**Post date:** [September 12, 2024, 8:42am UTC](https://discuss.ocaml.org/t/map-make-with-polymorphic-variant/15267/6 "2024-09-12T08:42:41Z")

</div>

Strongly agree here! There is a big difference between the polymorphic comparison C primitive (`caml_compare`, implemented in `runtime/compare.c`) and the lambda primitive `%compare` (`Stdlib.compare` is this latter one). It’s a shame to end up writing masses of code (and often generating more complex code) rather than a simple type annotation.

There’s a long tale of trying to get a warning into OCaml to be emitted when `caml_compare` is used instead of a monomorphised version in [Warn on polymorphic comparisons by kit-ty-kate · Pull Request #9928 · ocaml/ocaml · GitHub](https://github.com/ocaml/ocaml/pull/9928).

---

<div class="post-metadata">

**Author:** ![xvw](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/xvw/32/2041_2.png) [@xvw](https://discuss.ocaml.org/u/xvw)\
**Post date:** [September 12, 2024, 9:19am UTC](https://discuss.ocaml.org/t/map-make-with-polymorphic-variant/15267/7 "2024-09-12T09:19:55Z")

</div>

@sim642 and @dra27  
Thanks a lot for the clarification! I was not aware about that subtility!
