F#中度量单位的模式匹配

Old*_*vec 5 f# pattern-matching units-of-measurement

这个功能:

let convert (v: float<_>) =
  match v with
  | :? float<m> -> v / 0.1<m>
  | :? float<m/s> -> v / 0.2<m/s>
  | _ -> failwith "unknown"
Run Code Online (Sandbox Code Playgroud)

产生错误

类型'float <'u>'没有任何正确的子类型,不能用作类型测试或运行时强制的源.

有没有办法如何模式匹配度量单位?

Tom*_*cek 7

正如@kvb详细解释的那样,问题在于度量单位是该类型的一部分.这意味着它float<m>的类型不同float<m/s>(并且不幸的是,此信息不会在运行时存储为值的一部分).

所以,你实际上是在尝试编写一个可以使用两种不同类型输入的函数.干净的功能解决方案是声明一个可以保存第一种类型或第二种类型的值的区别联合:

type SomeValue = 
  | M of float<m>
  | MPS of float<m/s>
Run Code Online (Sandbox Code Playgroud)

然后你可以使用普通的模式匹配来编写函数:

let convert v = 
  match v with 
  | M v -> v / 0.1<m>
  | MPS v -> v / 0.2<m/s>
Run Code Online (Sandbox Code Playgroud)

您需要将值显式地包装到区分的union值中,但它可能是直接执行此操作的唯一方法(不会在程序结构中进行更大的更改).

对于像int和这样的普通类型float,您也可以使用重载成员(在某些F#类型中声明),但这对度量单位不起作用,因为在F#编译器擦除单位信息后签名将是相同的.