度量单位,接口和混合

时间:2011-08-03 01:21:29

标签: interface f# mixins units-of-measurement

考虑以下F#代码:

type ILinear =
  interface 
  end

type IMetric =
  interface
  end


[<Measure>] type cm =
    interface ILinear
    interface IMetric 

[<Measure>] type m =
    interface ILinear
    interface IMetric

[<Measure>] type time

我希望使用这些接口作为对度量类型进行分组的方法,并且作为允许“任何度量”和“特定度量”之间的一般性级别的方式 - 类似于:

(* Yes, I know this syntax is probably incorrect *)    
let rate (distance:float<'u:#ILinear,#IMetric>) (time:float<time>) =
       distance/time

我意识到这可能会推动可能性的限制,但我只是有点好奇,如果这是可能的,如果是这样,那将是什么语法。正如我所说,这是将接口用作穷人的混合物。

1 个答案:

答案 0 :(得分:5)

我不认为这是可能的,但我非常喜欢这个想法:-)。

如果可能的话,那么约束可能会使用与为普通(非度量)类型参数编写接口约束相同的语法编写:

let rate<[<Measure>] 'u when 'u :> IMetric> (distance:float<'u>) (time:float<time>) =
    distance/time

错误消息清楚地表明约束只能在普通类型参数上指定(实际上,我甚至惊讶于度量单位可以实现接口 - 它看起来并不是非常有用,因为它们在编译期间被完全擦除):

  

错误FS0703:预期的类型参数,而不是度量单位参数

我能想到的最佳解决方法是编写一个存储值(带有某个单位)的简单包装器和表示约束的附加(幻像)类型:

[<Struct>]    
type FloatValue<[<Measure>] 'u, 'constr>(value:float<'u>) =
  member x.Value = value

let cm f = FloatValue<_, IMetric>(f * 1.0<cm>)

cm函数使用float并将其包装到FloatValue中。第二个类型参数是普通类型参数,因此可以提供一些实现接口的类型(或仅使用单个接口)。然后rate函数如下所示:

let rate (distance:FloatValue<'u, #IMetric>) (time:float<time>) =
  distance.Value / time

由于无法在单元类型上指定约束,因此我们必须在第二个类型参数上指定它们。然后,您可以使用以下方法调用该函数:

rate (cm 10.0) 5.0<time>