我正在与度量单位在F#中玩耍,我目前正在尝试创建长度和质量的复合度量单位,以反映帝国系统中的口语讲话。在美国和英国,“我身高5英尺10”或“她重8磅11磅”。
我为标准(非复合)单元定义了一个模块,如下所示:
module Units
// Mass
[<Measure>] type kg // Kilogram
[<Measure>] type g // Gram
[<Measure>] type lb // Pound (mass)
[<Measure>] type st // Stone (mass)
// Conversions
...
// Length
[<Measure>] type m // Metre
[<Measure>] type cm // Centimetre
[<Measure>] type inch // Inch
[<Measure>] type ft // Foot
// Conversions
...
我在不同的模块中定义了复合单元:
module CompoundUnits
open Units
// Mass
type StonesAndPounds = {
Stones: float<st>
Pounds: float<lb>
}
// Length
type FeetAndInches = {
Feet: float<ft>
Inches: float<inch>
}
但是,按照我目前编写复合质量和长度类型的方式,存在非法状态(例如负值)和技术正确但不首选的状态的空间:
// 39 lbs = 2 st 11 lbs
let eightStoneEleven: StonesAndPounds = { Stones = 6.0<st>; Pounds = 39.0<lb> }
// 22" = 1' 10"
let fiveFootTen: FeetAndInches = { Feet = 4.0<ft>; Inches = 22.0<inch> }
在他的“领域建模使功能”一书中,斯科特·格拉斯钦谈到了使非法的州不可代表的问题,所以我想知道是否有办法对我的复合类型实施某种限制,以便0<ft> <= Feet
、0<inch> <= Inches <= 12<inch>
和0<st> <= Stones
、0<lb> <= Pounds <= 14<lb>
。
发布于 2021-08-11 01:36:35
一个常见的模式是为该类型创建一个模块,其中包含它的定义、create
函数和其他验证逻辑。
斯科特在他的网站上有一些例子,作为他的“类型设计”系列的一部分。
https://fsharpforfunandprofit.com/posts/designing-with-types-non-strings/
您不能强制对度量单位本身施加限制,但是可以创建专用类型来表示复合度量,就像Scott对SafeDate
和NonNegativeInt
等所做的那样。
对于它们的组件属性,它们仍然可以使用“标准”度量单位。
这篇文章的引文是:
“度量单位确实可以用来避免混淆不同类型的数值,而且比我们一直使用的单个大小写合并功能要强大得多。
另一方面,度量单位没有封装,也不能有限制。任何人都可以创建带有度量单位的int,例如,没有min或最大值。“
https://stackoverflow.com/questions/68700764
复制