计量单位的界限/域

时间:2011-07-16 19:19:01

标签: f# units-of-measurement validation

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

2 个答案:

答案 0 :(得分:6)

F#中的度量单位不支持行为。它们是在编译期间用于抛出类型错误的静态机制。您将需要一个对象来封装任何“行为”。例如,您可以创建一个type Temperature,为运算符提供绑定检查。如果您传递了-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>)

答案 1 :(得分:3)

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

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

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