The subtle thing in your code snippets is unbox float x
- the compiler treats this as (unbox float) x
. As a result the two functions are actually treated like this:
let intToFloat (x:int<'u>) : float<'u> =
let f = unbox float in f x
let float32ToFloat (x:float32<'u>) : float<'u> =
let f = unbox float in f x
So, you are taking the float
function, casting it (unsafely) to a function of another type and then calling it. The type is int<'u> -> float<'u>
in the first case and float32<'u> -> float<'u>
in the second case.
I think the first one works because when the compiler sees the float
function (without any type annotations), it defaults to int -> float
and, since units of measure are erased at runtime, this can be converted to int<'u> -> float<'u>
(but not to the second type - because you are performing unsafe cast).
So, the main problem is wrong parentheses in your implementation (which leads to a really subtle issue). I think you probably wanted something like this:
let intToFloat (x:int<'u>) : float<'u> = unbox (float x)
let float32ToFloat (x:float32<'u>) : float<'u> = unbox (float32 x)