【问题标题】:F# types with units of measure vs System.Math具有测量单位的 F# 类型与 System.Math
【发布时间】:2015-04-28 05:18:06
【问题描述】:

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

[<Measure>]
type rad

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

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

我创建了一段幼稚的代码,它允许函数也处理 float&lt;rad&gt; 值:

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

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

但它的问题是它完全不是通用的。假设我也想引入一个单位来表示学位 - 那么呢?我需要复制代码并将所有单位从“rad”更改为“deg”吗?或者也许有更好的解决方案?

【问题讨论】:

    标签: generics f# units-of-measurement


    【解决方案1】:

    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> ...
    

    在使用所有这些功能时,不知道单位的功能成为例外,在其余情况下手动添加或删除单位不是什么大问题。

    【讨论】:

      猜你喜欢
      • 2017-03-26
      • 2013-03-12
      • 1970-01-01
      • 2011-04-17
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 2011-03-31
      • 1970-01-01
      相关资源
      最近更新 更多