Is it possible to return a polymorphic function using Obj.magic?

It seems Obj.magic is not magical enough, I want to cast an expression to a polymorphic function type, below is a simple example:

let f : 'a -> unit = Obj.magic 3

In the end, it will complain that it contains variables that can not be generalized, I kinda know why it works this way, my question is that if there is a way to coerce an expression to an arbitrary type

let f = (coerce exp: 'a -> int ) (* or any type you want *)

Does this work?

type poly = {f: 'a. 'a -> int};;
  
let w = {f = Obj.magic 3};;

w.f

This would work for this case. It would be ideal if there is a mechanical way to break type system, the coerced type could be arbitrary function types

Isn’t this due to the value restriction rather than some property of Obj.magic?

Yes, it’s the value restriction. You just need an intermediary step:

# let x = Obj.magic 3 ;;
val x : 'a = <poly>
# let f : 'a -> int = x ;;
val f : 'a -> int = <fun>

Indeed, for people who are curious about what I want to do, in BuckleScript we want to allow people to insert arbitrary js code to get job done sometimes. Originally:

let forIn : 'a -> (string -> unit) -> unit = 
   fun%raw  o foo -> {|
  for (var i in o){
    foo(o)
  }
  |}

but the forIn is not really polymorphic, here is a temporary work around:

let forIn = 
   (fun%raw  o foo -> {|
  for (var i in o){
    foo(o)
  }
  |})

  let forIn : 'a -> (string -> unit) -> unit = forIn  

Let me know if you have some ideas to streamline the workflow, I know it is not cool to use Obj.magic, but it is important to ship than waiting everything to be perfect : )

Edit: it seems such work around only works for toplevel bindings not local bindings (let .. in)

The value restriction works in the same way for top level and local bindings:

let f () =
  let g = Obj.magic (fun (x : int) -> ()) in
  let h : 'a. 'a -> unit = g in
  h (), h 1

You may be running into an different issue, eg, non-generalisation of type variables from a level higher than the let. It’s hard to say without a concrete example…