Reputation: 11595
When should I NOT use Units of Measure?
I feel that any values that are used in calculations should have a unit of measure applied to it.
Are my thoughts accurate?
If they are, then why doesn't F# by default enforce this constraint to encourage correctness?
In my case, I used Units of Measure for a basketball game:
For example:
[<Measure>] type pts
type Player = { Score:int<pts> }
Here's the model that leverages units of measure:
(*Types*)
[<Measure>] type pts
type Player = { Score:int<pts> }
type FieldShot = TwoPointer| ThreePointer
type FoulShots = FoulShot | TwoFoulShots | ThreeFoulShots
type FoulShooter = FoulShooter of Player
type FieldShooter = FieldShooter of Player
(*Functions*)
let shoot (lastShot:int<pts>) player =
(player.Score + lastShot)
let fieldShot (fieldShooter, shot) =
let player = match fieldShooter with
| FieldShooter player -> player
match player.Score with
| score when score > 10<pts> -> score
| _ -> match (fieldShooter, shot) with
| FieldShooter player, shot -> match shot with
| TwoPointer -> player |> shoot 2<pts>
| ThreePointer -> player |> shoot 3<pts>
let foulShot (foulShooter, shot) =
let player = match foulShooter with
| FoulShooter player -> player
match player.Score with
| score when score >= 11<pts> -> score
| _ -> match (foulShooter, shot) with
| FoulShooter player, shot -> match shot with
| FoulShot -> player |> shoot 1<pts>
| TwoFoulShots -> player |> shoot 2<pts>
| ThreeFoulShots -> player |> shoot 3<pts>
let makeFoulShots foulShots (shooter, defender) =
FieldShooter { Score= foulShot (shooter, foulShots) }, defender
let makeFieldShot fieldBasket (shooter, defender) =
FoulShooter { Score= fieldShot (shooter, fieldBasket) }, defender
let turnover (shooter, defender) = (defender, shooter)
(*Client*)
let player1, player2 = FieldShooter { Score=0<pts> } ,
FieldShooter { Score=0<pts> }
let results = (player1, player2) |> makeFieldShot TwoPointer
|> makeFoulShots ThreeFoulShots
|> makeFieldShot TwoPointer
|> makeFoulShots TwoFoulShots
|> makeFieldShot TwoPointer
|> makeFoulShots FoulShot
Upvotes: 1
Views: 224
Reputation: 12184
Well, the only answer that springs to mind is that you should generally not use unit of measures for dimensionless quantities.
Consider values such as pi or e.
Dimensionless values often arise from ratios of quantities that do have some physical dimension.
Consider you want to create some program logic that triggers when one team's basket ball score reaches double the score of another team, you would need a dimensionless quantity:
if teamBScore >= 2 * teamAScore then
...
else
...
The value 2
has to be used in a calculation and has to be dimensionless or the units of teamAScore
and teamBScore
wouldn't match.
Of course, strictly speaking you could annotate such values with units of 1
explicitly but that's probably overkill.
Aside from that, the rest of the question is primarily opinion based. You should use or not use units of measure depending on how you assess the gain in safety you'll get at the cost of (slightly) increased programming time and verbosity.
Upvotes: 3
Reputation: 170745
If they are, then why doesn't F# by default enforce this constraint to encourage correctness?
For one, because it needs to interoperate with languages which don't support units of measure. If you want to use values coming from a C# library method in a computation, how can it decide what unit to use? Even if F# developers spend a lot of time annotating all the standard library methods with units of measure, this wouldn't help with third-party libraries.
Upvotes: 2