Je joue avec unités de mesure en F# et j'essaie actuellement de créer des unités de mesure composées pour la longueur et la masse afin de refléter le langage familier dans le système impérial, par exemple "Je mesure 1,5 m 10" ou "Elle pèse 2,5 kg" aux États-Unis et au Royaume-Uni.
J'ai défini un module pour les unités standard (non composées) comme suit :
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
...
Et j'ai défini les unités composées dans un autre module :
module CompoundUnits
open Units
// Mass
type StonesAndPounds = {
Stones: float<st>
Pounds: float<lb>
}
// Length
type FeetAndInches = {
Feet: float<ft>
Inches: float<inch>
}
Cependant, avec la manière dont j'ai actuellement écrit les types de masse et de longueur composées, il y a de la place pour des états illégaux (tels que des valeurs négatives) et des états qui sont techniquement correct mais pas de préférence :
// 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> }
Dans son livre "Domain Modeling made Functional", Scott Wlaschin parle de rendre les états illégaux non représentables. Je me demandais donc s'il existait un moyen d'appliquer une sorte de restriction sur mes types composés afin que 0<ft> <= Feet
, 0<inch> <= Inches <= 12<inch>
y 0<st> <= Stones
, 0<lb> <= Pounds <= 14<lb>
.