我正在学习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 /(h s)
答案 0 :(得分:17)
首先,您的msToKmph
完全不正确。虽然它返回了一个正确的返回值,它实际上正在做什么,只是 drop 原始<m/s>
值转换为普通的无量纲 {{1然后将无量纲值乘以float
。
为了更好地表达UoM之间的关系,请考虑以下事项:
3.6<km/h>
请注意,所有“幻数”都封装在UoM转换器中,因此您的公式保持干净,例如它们只是操作值和常量,但UoM由编译器计算。
更新:UoM转换的理念是转换公式应该是具有物理意义的东西。经验法则是您的转换价值是否出现在参考书中。用简单的英语,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
从上面来看是没用的,但3.6<km/h>
只是说,“1公里内有1000米”,这是有道理的。
您甚至可以像这样改进1000.0<m/km>
:
hrToSec
这将使每个值都成为参考书中的众所周知的价值。
答案 1 :(得分: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
对于km
和m
,通用解决方案是定义单位前缀k
,以便它适用于以千克作为指标的许多UoM:
[<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