1
votes

The root of the problem is with this external:

external make : string -> 'a -> unit = "debug"

which I need to use with any kind of type:

let debug = make "name:space:a"

let _ = debug "log this thing"
let _ = debug 42

Unfortunately this results in the following error on the last line:

This expression has type int but an expression was expected of type string

So I need to make the type parameter explicitly polymorphic, but from what I can understand this can for some reason only be done in type annotations attached to let bindings. Adding it to the external yields a syntax error. So I try:

let debug : 'a. 'a -> unit = make "name:space:a"

which of course results in the error:

This definition has type 'a -> unit which is less general than 'a0. 'a0 -> unit

So I try another way of cheating the system, and add this right after the external:

let make : 'a. string -> 'a -> unit = make

which to my surprise does NOT give me a similar type error on this line, but seems to just ignore the type annotation and continues to give me the same error on let debug ....

This leaves me very confused, and with the following questions:

  1. Is it really not possible to define an external with a polymorphic type?
  2. Regardless of the answer to 1, why is it not possible to use explicit polymorphic type annotations with externals?
  3. Why is the type annotation on let make ... completely ignored?

Note: I'm using BuckleScript, which is on 4.02.3. Online playground here.

1

1 Answers

4
votes

This is the value restriction, not a consequence of using external. (Previous discussion, one of many: The value restriction.)

Your definition of debug is a function application, so it can't be generalized (made polymorphic).

The solution is to do eta expansion:

let debug x = make "name:space:a" x

Now your definition of debug is a lambda, which can be generalized.

(Previous discussion of eta expansion: Why does OCaml sometimes require eta expansion?)