【问题标题】:f# function call with parameters and cast to units of measuref# 带参数的函数调用并转换为度量单位
【发布时间】:2014-12-19 01:51:18
【问题描述】:

我喜欢用 F# 编写一些数学函数并在 C# 中使用它们。由于 F# 使用度量单位,因此进行编译时检查真的很棒。在 C# 中,我已经有一个 Length(转换为 m、mm、km 等的索引器)类,因此我想使用 F# 函数将其用作 C# 中的参数,并将其转换为浮点数或更具体的浮点数。

由于我有两个参数,我很难调用这些函数。我想这与currying有关。

module Static
open Xunit
open Units.Contract // here is my Length class defined in C#

[<Measure>] type m
[<Measure>] type slabThickness = m
[<Measure>] type kN
[<Measure>] type freshConcreteDensity = kN/m^3
[<Measure>] type freshConcreteLoad = kN/m^2


let FreshConcreteLoad(slabThickness:float<m>, freshConcreteDensity:float<kN/m^3>) = slabThickness * freshConcreteDensity // 1. works

let FreshConcreteLoadL(slabThickness:Length, freshConcreteDensity:Length) = slabThickness.[Length.Units.m] *  freshConcreteDensity.[Length.Units.m] //2. works

let FreshConcreteLoadLUseMeasure(slabThickness:Length, freshConcreteDensity:Length) =  FreshConcreteLoad (slabThickness.[Length.Units.m]:float<m> freshConcreteDensity.[Length.Units.m]:float<kN/m^3>)  //3. here I struggel

// Related to 1. and works
[<Fact>]
let FreshConcreteLoad_Test() = 
    let thickness =  0.2<slabThickness>
    let density =  25.0<freshConcreteDensity> 
    let load:float<freshConcreteLoad> = FreshConcreteLoad(thickness,density)  
    Assert.Equal(load, 5.0<kN/m^2>) 

// Related to 2. and works
[<Fact>]
let FreshConcreteLoadL_Test() = 
    let thickness = new Length(0.2)
    let density = new Length(25.0) // dont care that this is now also a length, just for testing. in real live here would be a class for kN
    let load:float = FreshConcreteLoadL(thickness,density)  
    Assert.Equal(load, 5.0)

// Related to 3. and I struggle with the function call
[<Fact>]
let FreshConcreteLoadLUseMeasure_Test() = 
    let thickness = new Length(0.2)
    let density = new Length(25.0) // dont care that this is now also a length, just for testing. in real live here would be a class for kN
    let load:float = FreshConcreteLoadLUseMeasure(thickness,density)  
    Assert.Equal(load, 5.0)

【问题讨论】:

    标签: c# casting f# units-of-measurement function-calls


    【解决方案1】:

    您的 3. 函数定义不是有效的 F# 函数定义。如果您需要调用另一个函数“FreshConcreteLoad()”,则不能在函数调用中使用类型注释。 也许您想将函数参数转换为度量单位,但无法执行此转换,因为 C# 中不存在 F# 度量单位,因此无法将 C# 值直接转换为它。

    您可以做的是创建几个转换 F# 函数的助手,例如:

    let convToLength (inp: float) = inp * 1.0<m>
    let convToDensity (inp: float) = inp * 1.0<kN/m^3>
    

    并将第三个函数定义为:

    let FreshConcreteLoadLUseMeasure(slabThickness:Length, freshConcreteDensity:Length) =  FreshConcreteLoad (convToLength slabThickness.[Length.Units.m], convToDensity freshConcreteDensity.[Length.Units.m]) 
    

    或者直接在调用中进行转换:

    let FreshConcreteLoadLUseMeasure(slabThickness:Length, freshConcreteDensity:Length) =  FreshConcreteLoad (1.0<m> * slabThickness.[Length.Units.m], 1.0<kN/m^3> * freshConcreteDensity.[Length.Units.m])
    

    【讨论】:

    • 太好了,谢谢。这就是解决方案。现在我只需要考虑一个比使用 C# 中的 Length 对象更快的解决方案。使用双精度/浮点数要快得多,但你很容易犯错误,因为在 C# 中使用 float 时它只是双精度数。所以参数顺序和度量单位可能是错误的。有什么想法或对另一个问题有好处吗? :)
    • 很难说。也许在 C# side Length { public float value; 上使用 struct public Unit uom /*并使用枚举作为度量单位类型*/ }
    猜你喜欢
    • 2018-02-05
    • 2011-04-17
    • 1970-01-01
    • 2018-06-15
    • 2012-07-05
    • 1970-01-01
    • 2013-04-09
    • 1970-01-01
    • 2019-02-25
    相关资源
    最近更新 更多