【发布时间】:2016-08-03 20:26:06
【问题描述】:
什么时候不应该使用计量单位?
我觉得计算中使用的任何值都应该有一个计量单位。
我的想法准确吗?
如果是,那么为什么 F# 默认不强制执行此约束以鼓励正确性?
就我而言,我在篮球比赛中使用了度量单位:
例如:
[<Measure>] type pts
type Player = { Score:int<pts> }
这是利用计量单位的模型:
(*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
【问题讨论】:
-
我相信在你的情况下使用 UOM 不会给程序带来任何有用的东西,因为你不用不同的单位进行计算。例如,如果您有以
和 表示长度的值,这可能会很有用。 -
当数字有一些额外的元数据时(例如屏幕/纸张坐标),UOM 可能很有用(在模拟之外)。一件事可能是区分以不同方式得分的分数。但是您总是需要至少两种不同类型的数字,否则您只是在浪费时间
-
单位也将被删除,因此如果您在运行时互操作或需要它们,那么您就不走运了:运行时的单位测量单位用于静态类型检查。编译浮点值时,会消除测量单位,因此在运行时会丢失单位。因此,任何试图实现依赖于在运行时检查单元的功能都是不可能的。例如,实现 ToString 函数来打印单位是不可能的。
-
我开始怀疑 F# 是否不是您应该用来学习函数式编程的语言。正如我所指出的,由于使用 .NET 实现并来自 OCaml,F# 的功能受到限制。这不是一件坏事,您只需要在创建解决方案时了解它可以做什么和不能做什么。虽然我不知道 Haskell,但计划,也许你应该学习 Haskell,然后再回到 F#。我认识的许多最优秀的 F# 程序员也知道 Haskell。
-
@ScottNimrod 不,我不认为将度量单位作为预防机制是过度设计的。添加单位几乎没有任何成本 - 请注意,在您的示例中,您可以省略几乎所有的
<pts>并替换为<_>。在更真实的代码中,您甚至不会经常看到<_>。我不得不承认,我是度量单位的忠实粉丝(我维护着一个庞大的 F# 代码库),并且单位在无数场合都拯救了这一天。