Domanda

This came up while I looked at the following question: F# Unit of Measure, Casting without losing the measure type Please note that I am not trying to use this unbox code, I just discovered some weird behavior while answering the question.

Why does the following code work

let intToFloat (x:int<'u>) : float<'u> = unbox float x
intToFloat 1<second>

while this yields a System.InvalidCastException: Unable to cast object of type 'float32ToFloat@86-6' to type 'Microsoft.FSharp.Core.FSharpFunc`2[System.Single,System.Double]'.?

let float32ToFloat (x:float32<'u>) : float<'u> = unbox float x
float32ToFloat 1.0f<second>

If I put parantheses around the (float x) the code works as expected, so I assume it must be some expression evaluation/type inference rule. What exactly is going on here and why are the parantheses needed in the second case?

È stato utile?

Soluzione

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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top