8

我正在学习 F# - 目前正在研究计量单位。我有一个返回米每秒的简单计算,我想介绍一个将其转换为每小时公里数的函数。

我的代码如下所示:

[<Measure>] type kg
[<Measure>] type s
[<Measure>] type m
[<Measure>] type km
[<Measure>] type h            

let msToKmph(speed : float<m/s>) =
    (float speed) * 3.6<km/h>

let gravityOnEarth = 9.81<m/s^2>
let heightOfJump = 3.5<m>

let speedOfImpact = sqrt (2.0 * gravityOnEarth * heightOfJump)
let speedOfImpactKmh = msToKmph(speedOfImpact)

这行得通 - 我得到 8.28673639 m/s 和 29.832251 km/h。我不确定这是否是表达不同单位之间关系的最佳方式。这可以更优雅地完成吗?

例如,行(浮动速度)从速度参数中删除单位信息,使 msToKmph 返回 km/h。如果我在计算之前没有删除单位信息,则返回的单位为:km m/(hs)

4

2 回答 2

17

首先,你msToKmph是完全不正确的。虽然它返回一个正确的返回值,但它实际上在做什么,它只是通过转换为一个普通的、无量度的,然后将无量度的值乘以 a 来降低原始值。<m/s> float3.6<km/h>

为了更好地表达计量单位之间的关系,请考虑以下内容:

let kmToM = 1000.0<m/km>  // relation between kilometers and meters
let hrToSec = 3600.0<s/h> // relation between seconds and hours
let msToKmph(speed : float<m/s>) =
    speed / kmToM * hrToSec

请注意,所有“幻数”都封装在 UoM 转换器中,因此您的公式保持干净,例如它们只是操作值和常量,但 UoM 是由编译器计算的。

更新:计量单位转换的理念是转换公式应该是具有物理意义的东西。经验法则是您的转化价值是否出现在参考书中。用简单的英语来说,3.6<km/h>从上面看是没有用的,1000.0<m/km>只是说“1公里有1000米”,这是有道理的。

你甚至可以hrToSec像这样改进:

let hrToSec2 = 60.0<s/minute> * 60.0<minute/h>

这将使每个值都成为参考书中的众所周知的值。

于 2012-12-11T15:01:25.070 回答
4

你说得对,删除单位信息是一件坏事。您应该创建一些具有适当单位的常量以进行转换。

let mPerKm = 1000.0<m/km>
let secondPerHour = 3600.0<s/h>

// val msToKmph : float<m/s> -> float<km/h>
let msToKmph(speed : float<m/s>) =
    speed / mPerKm * secondPerHour

对于kmm,一个通用的解决方案是定义一个单位前缀k,以便它适用于许多以千为度量的计量单位:

[<Measure>] type k

let kilo = 1000.0<1/k>
let secondPerHour = 3600.0<s/h>

// val msToKmph : float<m/s> -> float<k m/h>
let msToKmph(speed : float<m/s>) =
    speed / kilo * secondPerHour
于 2012-12-11T15:02:06.827 回答