为什么这个度量单位被限制为1?

时间:2011-03-11 06:51:49

标签: f# interop units-of-measurement

我需要能够用F#中的几个不同单位表示相同的概念。例如,我想用光年,天文单位,公里和米表示“距离”。我想使用泛型函数来计算这些值。这就是我将ly,AU,km和m组合在一起的方式:

[<Measure>] type ly
[<Measure>] type AU
[<Measure>] type km
[<Measure>] type m

[<Measure>] type distance

type UnitValue<[<Measure>] 'u, [<Measure>] 't> =
    val conversionFactor : float<'t / 'u>
    val value : float<'u>
    new (v, cf) = { value = FloatWithMeasure<'u> v; conversionFactor = FloatWithMeasure<'t / 'u> cf }
    member this.toUnits = this.value * this.conversionFactor
    member this.fromUnits (x : float<'t>) = x / this.conversionFactor
    static member (+) (a : UnitValue<'u, 't>, b : UnitValue<_, 't>) =
        a.newValue (a.toUnits + b.toUnits)
    static member (-) (a : UnitValue<'u, 't>, b : UnitValue<_, 't>) =
        a.newValue (a.toUnits - b.toUnits)
    static member (*) (a : UnitValue<'u, 't>, b : float) =
        a.newValue (a.toUnits * b)
    member this.newValue (x : float<'t>) =
        new UnitValue<'u, 't>(float (this.fromUnits x), float this.conversionFactor)

//Distance units
type LightYearValue(value) =
    inherit UnitValue<ly, distance>(value, 6324.0)

type AstronomicalUnitValue(value) =
    inherit UnitValue<AU, distance>(value, 15.0)

type KilometerValue(value) =
    inherit UnitValue<km, distance>(value, 0.00001)

type MeterValue(value) =
    inherit UnitValue<m, distance>(value, 0.0000000)

这个代码是从单元不知道的C#中调用的,可以通过指定new LightYearValue(4.2)来完成,它将成为F#中的UnitValue<ly, distance>,并且可以传递给期望{{1}的函数}}。这样,适当的单位进入功能,适当的单位出去。例如,如果我通过函数a UnitValue<_, distance>,我可能会根据计算得到UnitValue<AU, distance> - 这对于比例来说是一个合适的数字。

对此感到非常满意,我开始写一个Orbit类型:

float<AU / s ^ 2>

但当我将鼠标悬停在and Orbit(PeR : UnitValue<_, distance>, ApR : UnitValue<_, distance>, AgP : float, focus : SphericalMass) = let PeR = PeR let ApR = ApR let AgP = AgP let focus = focus let Maj = PeR + ApR let Ecc = (Maj.value - (2.0 * PeR.value)) / Maj.value let DistanceAt theta = (Maj.value / 2.0) * (1.0 - Ecc ** 2.0) / (1.0 + Ecc * Math.Cos(theta)) 上时,它表示其类型为PeR。什么给出了什么?为什么这不起作用?我可以写一个函数UnitValue<1, distance>,它工作正常!它可能与C#与此代码交互有关吗? (类型由C#类扩展)有没有办法使这项工作:(

1 个答案:

答案 0 :(得分:3)

声明类型时,需要明确声明泛型类型参数(以及单位参数)。以下声明正确推断了类型:

type Orbit<[<Measure>] 'u, [<Measure>] 'v> 
    ( PeR : UnitValue<'u, distance>, ApR : UnitValue<'v, distance>,
      AgP : float, focus : SphericalMass) =
  let Maj = PeR + ApR
  let Ecc = (Maj.value - (2.0 * PeR.value)) / Maj.value
  let DistanceAt theta =
      (Maj.value / 2.0) * (1.0 - Ecc ** 2.0) / (1.0 + Ecc * Math.Cos(theta))

(顺便说一句:您不需要为本地let绑定重新分配参数 - 它们可以自动访问,因此我删除了let ApR = ApR)等行