I am having a major issue handling units of measure in F#. I have handled them successfully so far, but I have only either been removing units to get back a float or casting a float to one with units. However, now I have a use case where I need to generically drop units off of a float and give them new units. At present, I see no way that this is possible in F#.
For example:
> let removeUnits (x: float<'Unit>) = float x;;
val removeUnits: x: float<'Unit> -> float
> let castUnits<[<Measure>] 'Unit> (x: float) = LanguagePrimitives.FloatWithMeasure<'Unit> x;;
val castUnits: x: float -> float<'Unit>
> let convertUnits<[<Measure>] 'NewUnit> (x: float<'OldUnit>) : float<'NewUnit> =
x |> removeUnits |> castUnits<'NewUnit>;;
let convertUnits<[<Measure>] 'NewUnit> (x: float<'OldUnit>) : float<'NewUnit> =
-------------------------------------------------^^^^^^^^
stdin(8,47): warning FS0064: This construct causes code to be less generic than indicated by the type annotations. The unit-of-measure variable 'OldUnit has been constrained to be measure '1'.
val convertUnits: x: float -> float<'NewUnit>
This almost seems like a bug to me. The types of the pipeline should be float<'OldUnit> -> float -> float<'NewUnit>, because those are the type signatures of the component functions. I'm not understanding why out of nowhere that 'OldUnit is being constrained to 1.
How can I do this properly? I want a function with signature val convertUnits: x: float<'OldUnit> -> float<'NewUnit>, where the function only changes the units and leaves the underlying float values alone.
Is this a bug in the compiler?