1

我发现 F# 度量单位的想法非常吸引人。但是,通常情况下,某些单元具有它们所在的特定域。例如,距离是正数,温度大于开尔文零,概率在 0 和 1 之间,等等 - 但是我还没有看到任何内置的东西来代表这个概念,并验证一个特定的值是一个特定单位的有效度量。度量单位是否支持这样的东西(我不这么认为),如果不支持,是否有推荐的方法来实现该行为?

4

2 回答 2

6

F# 中的度量单位不支持行为。它们是编译期间用于抛出类型错误的静态机制。您将需要一个对象来封装任何“行为”。例如,您可以制作一个type Temperature为边界检查提供运算符的 a。如果您传递了该对象,则该对象可能会引发异常-1.0<Kelvin>

你可以做这样的事情。

[<Measure>] 
type Kelvin =
    static member ToCelsius kelvin =
        (kelvin - 273.15<Kelvin>) * 1.0<Celsius/Kelvin>

and [<Measure>] Celsius = 
    static member ToKelvin celsius =
        (celsius + 273.15<Celsius>) * 1.0<Kelvin/Celsius>

type Temperature(kelvin : float<Kelvin>) =
    do
        if kelvin < 0.0<Kelvin> then
            failwith "Negative Kelvin Temperature"

    member this.Celsius with get() = Kelvin.ToCelsius kelvin
    member this.Kelvin with get() = kelvin

    // could add operators here like (=) or (+)

let good = Temperature(0.0<Kelvin>)
let bad = Temperature(-1.0<Kelvin>)
于 2011-07-16T19:58:38.500 回答
3

正如 gradbot 已经说过的,F# 度量单位仅在编译时使用。不幸的是,你不能写出某个单位的值必须大于零的条件(这很难在编译器中检查)。

由于测量单位在运行时也不存在,因此您不能编写通用函数来获取任何温度并检查值是否具有单位Kelvin并且小于零(然后抛出异常)。您必须编写不同的包装器类型(例如TemperatureK,对于 type 的值float<Kelvin>)。

更好的选择可能是使用在运行时跟踪测量单位的库。然后您可以在运行时获取该单元并实施检查。Phil Trelford 实现了一个不错的运行时度量单位库,可能值得一试。

于 2011-07-16T20:17:35.327 回答