F#测量单位:从弧度到速度,单位为m / s

时间:2011-11-29 09:26:29

标签: f# measure

假设我已经定义了一个用于处理三维向量和度量单位的F#模块:

[<Measure>]
type m
[<Measure>]
type s
[<Measure>]
type v = m/s
[<Measure>]
type rad

type Vector3<[<Measure>] 'a> =
    {
    X : float<'a>
    Y : float<'a>
    Z : float<'a>
    }

在某个地方,我有一个以弧度表示的角度:

let angle:float32<rad> = 0.5f<rad>

现在我必须使用角度声明Vector3(力度)来计算其组件。我试过像:

let velocity : Vector3<m/s> = { X = Math.Cos(angle);Y = Math.Sin(angle);Z = 0.0<m/s>} //don't compile

上面的代码无法编译,因为Vector3期望X和Y中的值,但Sin返回一个浮点数。

我该如何解决这个问题?如果可能的话,我想在测量单位之间进行转换,而不是使用强制转换,这样编译器可以保证在将角度转换为速度时我做的是正确的。

有什么建议吗?

3 个答案:

答案 0 :(得分:4)

这里有几个问题: cos期待无单位值,因此您必须关闭单位angle;如果速度期望float而不是float32,您也可以直接转换为float(删除单位)。

然后,您需要重新打开设备。在度量单位的第一个版本中,您可以通过在适当的度量中乘以1来实现此目的。现在有LanguagePrimitives.FloatWithMeasure,这更正确,但稍微冗长。

let velocity =
 {
     X = angle |> float |> cos |> LanguagePrimitives.FloatWithMeasure<m/s> ;
     Y = angle |> float |> sin |> LanguagePrimitives.FloatWithMeasure<m/s> ;
     Z = 0.0<m/s> ;
 }

除此之外,10弧度是一个有趣的角度......

(请注意cossin是内置的)

答案 1 :(得分:1)

  

如果可能,我想在度量之间执行转换   单元,而不是演员,以编译器可以这样的方式   保证我在转换角度时做的正确   进入速度。

你要求相互矛盾的事情。计量单位通过使用类型推断来强制执行程序中的单元,有助于保证程序的正确性,因此必须明确地进行转换。

正如@Benjol所说,你必须在维度和无量纲数据之间进行转换。下面的代码是一个非正式版本,我将其从float转换为float<m/s>乘以其单位值:

let angle:float32<rad> = 0.5f<rad>

let velocity = {
                X = sin (float angle) * 1.0<m/s> ; 
                Y = cos (float angle) * 1.0<_> ; 
                Z = 0.0<_>
               } 

请注意,您只需为X指定单位,其他单位将根据Vector3的类型声明推断。

答案 2 :(得分:1)

好的,这是另一个展示,展示了如何结合标量速度和二维方向来真正利用你的单位:

let vvector (velocity:float<'u>) (xydirection:float<rad>) =
    { 
        X = cos (float xydirection) * velocity;
        Y = sin (float xydirection) * velocity;
        Z = 0.<_>
    }

给出了:

> vvector 15.3<m/s> angle<rad>;;
val it : Vector3<m/s> = {X = 13.4270132;
                         Y = 7.335210741;
                         Z = 0.0;}

您可以通过向Vector3类型添加运算符来更进一步:

static member (*) (v1: Vector3<'u>, n: float<'v>) =
    { X = v1.X * n; Y = v1.Y * n; Z = v1.Z * n }

这意味着你可以这样做:

let vvector2 (velocity:float<'u>) (xydirection:float<rad>) =
    { X = cos(float xydirection); Y = sin(float xydirection); Z = 0. } * velocity

显然,你还没有真正“使用”你的弧度,但这有点预期,无论如何,弧度都是'非'单位。 可以使用它们的一种方法是,如果您希望能够管理弧度度。您可以在Vector3上添加另外两个静态成员:

static member ofAngle (ang:float<rad>) = 
    { X = cos(float ang); Y = sin(float ang); Z = 0.0 }
static member ofAngle (ang:float<degree>) = 
    Vector3<'u>.ofAngle(ang * 2.<rad> * System.Math.PI / 360.<degree>)

看起来很不错,但遗憾的是它无法编译,因为The method 'ofAngle' has the same name and signature as another method in this type once tuples, functions and/or units of measure are erased.您可以查看this question了解更多详情