具有度量单位与System.Math的F#类型

时间:2015-02-26 00:02:31

标签: generics f# units-of-measurement

我定义了自己的度量单位来表示弧度:

[<Measure>]
type rad

然后我意识到有一个值,例如类型float<rad>我不能使用System.Math中定义的许多函数(因为它们使用&#39;普通&#39;浮点数)

let valueWithUnit = 5.45<rad>
let absValue = Math.Abs valueWithUnit // <--- error!!

我创建了一段天真的代码,允许函数处理float<rad>值:

let liftToRadFunc (f : float -> float) (arg : float<rad>) =
    arg * 1.</rad>
    |> f
    |> (*) 1.<rad>

let result = (liftToRadFunc Math.Abs) valueWithUnit // <--- now works fine

但问题在于它完全不是通用的。假设我想引入一个单位来代表学位 - 那么呢?我是否需要复制代码并更改&#34; rad&#34;中的所有单位?去&#34;度&#34; ?或者可能有更好的解决方案?

1 个答案:

答案 0 :(得分:3)

F#的core operators主要是测量单位。例如,abs使用度量单位并使System.Math.Abs冗余。

可以根据使用的单位来概括问题中的函数:

let liftToKeepUnits f (arg : float<'u>) : float<'u> =
    float arg |> f |> LanguagePrimitives.FloatWithMeasure

虽然这只是保留单位,但只有在功能对单位没有影响时才正确。因此,我将使用此提升功能来创建特定的单元感知功能,而不是在使用它们时提升功能。

根据我的经验,最有用的工具是能够根据度量单位制作通用类型和功能。类型推断并不总是单独执行此操作,但添加度量单位类型注释通常可以解决问题。在更复杂的情况下,LanguagePrimitives.FloatWithMeasureLanguagePrimitives.Float32WithMeasure允许与类型注释一起添加单元,否则将会遇到使用通用度量单位参数禁止非零值的约束。

此外,类型可以包含这样的度量单位参数:

type MyType<[<Measure>] 'u> ...

使用所有这些功能时,不了解单位的功能会成为例外,在其余情况下手动添加或删除单位并不是一个大问题。