【发布时间】:2021-09-29 03:53:11
【问题描述】:
这可能是不可能的,但我觉得我可能会学到一些东西,或者可能有一种截然不同的方法来处理它。
我正在编写一些包含一些物理模拟元素的代码,并且我可能正在处理一堆不同的单元。我觉得让类型系统在这方面为我做一些工作是值得的,这样我就不能,例如,为距离增加质量或类似的东西。
这很容易:
module Mass : sig
type t
val sum : t -> t -> t
...
end = struct
type t = int
let sum = +
...
end
module Distance : sig
type t
val sum : t -> t -> t
...
end = struct
type t = int
let sum = +
...
end
现在编译器会阻止我尝试混合两者(对吗?)。类似的东西也应该可以用来表达相同类型的单位(例如,磅与千克),甚至可能使我免受某些精度或溢出错误的影响。到目前为止很容易。有趣/困难的部分是我想制作一个流畅的框架来处理单位组合,例如米每秒平方等。
我可以通过玩函子来接近:
module MakeProduct(F : UnitT)(S: UnitT) = struct
type t = (F.t, S.t)
...
end
module MakeRatio(Numerator : UnitT)(Denominator: UnitT) = struct
type t = (Numerator.t, Denominator.t)
...
end
然后我就可以了
module MetersPerSecondSquared = MakeRatio(MakeRatio(Meter)( Second))(Second)
会有一些非常笨拙的函数名称,但这应该会给我一个类型安全的系统,我可以在其中将25 m/s^2 乘以5s 并得到125m/s.
除了笨拙之外,我看到的问题是系统无法识别以不同顺序表达相同事物的类型。例如,我也可以将上述表述为:
MakeRatio(Meter)(Product(Second)(Second))
两者最终都应该表达相同的概念,但我不知道如何告诉类型系统它们是相同的,或者您仍然应该能够将第二个乘以 5s 并得到结果在m/s。
我想学习的是:
- 到底有没有办法让这个想法发挥作用?
- 如果没有,是否有形式/理论上的原因这很难? (仅用于我自己的教育)
- 是否有完全不同的方法来干净地处理类型系统中的不同单元?
【问题讨论】:
-
This exists in F#。它确实需要一些努力以一种非痛苦的方式来实现,例如不必在表达相同单位的等效方式之间进行痛苦的转换。
-
如果你想表达这个想法而不把它内置到语言中,你至少需要类型级别的算术。然后,您将您的单位表示为类型级整数(或者更好的是,有理数)的元组,这些整数或有理数代表指数。像 kg^1, m^2, s^-2) 或 (s^(1/2)) 之类的东西(我省略了零指数,但所有指数始终存在于所有基本量中,元组具有固定数量的元素) .然后,您可以将两个具有相同指数元组的量相加,并乘以任意量,结果的指数是这些操作数的和。
-
@n.1.8e9-where's-my-sharem。我不确定 OCaml 有什么扩展,但它不需要是无序元组吗?我真的不知道如何表达(我可以说
(int * string)或(string * int),但我不确定如何表达未排序的版本......那叫什么?) -
它应该被订购,
int * int * int(在类型级别)总是意味着(质量、距离、时间)您需要选择一组基本数量并坚持下去。这个例子有 3 个,SI 有 7 个。
标签: types ocaml units-of-measurement