Search code examples
ocamlffireasonbucklescriptvalue-restriction

Unable to type polymorphic [%bs.raw function


1) Is there a way to type this? 2) Anyone able to expound on these error messages?

let identity1: 'a => 'a = [%bs.raw {|
  function(value) {
    return value
  }
|}];

/*
Line 2, 11: The type of this expression, '_a -> '_a, contains type variables that cannot be generalized
*/

let identity2: 'a. 'a => 'a = [%bs.raw {|
  function(value) {
    return value
  }
|}];

/*
Line 8, 11: This definition has type 'a -> 'a which is less general than 'a0. 'a0 -> 'a0
*/

https://reasonml.github.io/en/try.html?reason=FAGwpgLgBAlgJmAdhGECeBGAXFA5AQygF4A%20PQoqAbQFIAjAZwDoAnfAdygG8AfYKKADMArogDGKAPaIAFADd8IYWACU3fgKgtIwloigKlYDQF9gPEwF0A3MGAB6AFTAAMjERgoAJgA0UDNhQACoAFp7oAA6ekoJQECEwDFBgAB4R2gwMMNJ%20uAD6hAC0ZPn4fmLSEPjuSZGeCiww%20HTgtSH40GL4iIiS0HSeAOZIYGwgMABeYHDAjvZ24NDwSCjoXjgETOTEJRTU9MxsnLwaIuJSsobKalwaAtoQuvpXxgJmFjZ2Tq7ungAcfgCOFCiSgCEE7lQ2X07VqaCi22K23YCTEIVgSVaSWGHjGcXa%20gIAAYtsSoEjibN5kA


Solution

  • bs.raw is effectful (expansive to be precise), therefore it is subject to the value restriction: http://caml.inria.fr/pub/docs/manual-ocaml/polymorphism.html#sec51 .

    In brief, the type of the result of a function application cannot be generalized, because it may have captured some hidden references. For instance, consider the function:

    let fake_id () = let store = ref None in fun y ->
      match !store with
      | None -> y
      | Some x -> store := Some x; y
    
    let not_id = fake_id ()
    let x = not_id 3
    

    then the next application of not_id will be 3. Therefore the type of not_id cannot be ∀'a. 'a -> 'a. That's why, the type-checker infers for your function the type '_weak1 -> '_weak1 (using 4.06 notation). This type _weak1 is not a polymorphic type but a placeholder for a yet unknown concrete type.

    In a normal setting, the solution is to make not_id a value with η-expansion:

     let id x = fake_id () x 
     (* or *)
     let id: 'a. 'a -> 'a = fun x -> fake_id () x