维护跨类型转换的度量单位

时间:2012-02-23 01:52:17

标签: f# units-of-measurement

如果我们定义一个度量单位,如:

[<Measure>] type s

然后是一个带度量的整数

let t = 1<s>

然后将其转换为浮动

let r = float t

我们看到r = 1.0没有度量类型。这似乎很奇怪,因为所有的测量信息都已丢失。

您可以使用LanguagePrimitives.FloatWithMeasure转换回类似

的浮点数
let inline floatMeasure (arg:int<'t>) : (float<'t>) =
    LanguagePrimitives.FloatWithMeasure (float arg)

强制执行正确的类型,但这不是正确的解决方案,因为测量单位的文档(http://msdn.microsoft.com/en-us/library/dd233243.aspx)说

  

但是,对于编写互操作性层,还有一些显式函数可用于将无单位值转换为具有单位的值。它们位于Microsoft.FSharp.Core.LanguagePrimitives模块中。例如,要从无单元浮点数转换为浮点数,请使用FloatWithMeasure,如以下代码所示。

这似乎表明在F#代码中应避免使用该函数。

是否有更惯用的方式来做到这一点?

2 个答案:

答案 0 :(得分:1)

(警告:我没有在愤怒中使用单位。)

我认为使用例如FloatWithMeasure是单位投射方面(无统一的单位)。我认为这在概念上与数字表示 - 投射方面正交(例如intfloat)。但是(我认为)没有库函数来对单位值进行数值表示式转换。也许这反映了这样一个事实:大多数单元值模拟真实世界的连续值,因为像int这样的离散表示通常不会用于它们(例如1<s>感觉错误;当然你的意思是{{1 }})。

所以我认为'表示'然后'重新调整单位'是好的,但是我想知道你是如何得到具有不同表示的值的,因为通常这些表示被修复为域(例如,到处使用1.0<s>

(在任何情况下,我都喜欢你的float函数,它从表示方面解除单位方面的混淆,所以如果你只需要改变表示,你就有办法表达直接。)

答案 1 :(得分:1)

这里的工作代码段完全符合您的要求,但会发出警告

  

stdin(9,48):警告FS0042:不推荐使用此结构:它仅用于F#库)):

[<NoDynamicInvocation>]
let inline convert (t: int<'u>) : float<'u> = (# "" t : 'U #)

[<Measure>] type s
let t = 1<s>
let t1 = convert t // t1: float<s>

但是,我不建议采用这种方法 首先,UoM是编译时,而类型转换let r = float t是运行时。在调用时,int -> float不知道它是int<s>还是int<something_else>。因此,它无法在运行时推断出正确的float<'u>

另一个想法是,UoM背后的哲学比它描述的更广泛。这就像说编译器,&#34;它是int,但请将其视为int<s>&#34;。目标是避免偶尔使用不当(例如,将int<s>添加到int<hours>) 有时候int -> float转换毫无意义:想到int<ticks>,就没有float<ticks>的感觉。

Further reading,指向@kvb指的是这篇文章。