lthms' avatar, a hand drawing looking person, wearing a headset, close to a window on a raining night
Thomas Letan
lthms · he/him

Did you come across something which caught your attention? Don’t hesitate to shoot me an email in my public inbox.

 Published on  Modified on

Writing a Function Whose Argument is a Polymorphic Function in OCaml

In OCaml, it is not possible to write a function whose argument is a polymorphic function. Trying to write such a function results in the type-checker complaining back at you.

let foo (type a b) id (x : a) (y : b) = (id x, id y)
Line 1, characters 50-51:
1 | let foo (type a b) id (x : a) (y : b) = (id x, id y);;
                                                      ^
Error: This expression has type b but an expression was expected
of type a

When OCaml tries to type check foo, it infers id expects an argument of type a because of id x, then fails when trying to type check id y.

The trick to be able to write foo is to use records. Indeed, while the argument of a function cannot be polymorphic, the field of a record can. This effectively makes it possible to write foo, at the cost of a level of indirection.

type id = {id : 'a. 'a -> 'a}

let foo {id} x y = (id x, id y)

From a runtime perspective, it is possible to tell OCaml to remove the introduced indirection with the unboxed annotation. There is nothing we can do in the source, though. We need to destruct id in foo, and we need to construct it at its call site.

g {id = fun x -> x}

As a consequence, this solution is not a silver bullet, but it is an option that is worth considering if, e.g., it allows us to export a cleaner API to the consumer of a module. Personally, I have been considering this trick recently to remove the need for a library to be implemented as a functor.