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