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