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 *)
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…