вызов функции f# с параметрами и приведением к единицам измерения

Мне нравится писать некоторые математические функции на F# и использовать их на C#. Поскольку в F# используются единицы измерения, очень удобно иметь проверку во время компиляции. В С# у меня уже есть класс Length (индексатор, который преобразуется в м, мм, км и т. д.), поэтому я хочу использовать его в качестве параметра из С# с помощью функции F# и преобразовать его там в число с плавающей запятой или более конкретное число с плавающей запятой.

Поскольку у меня есть два параметра, я изо всех сил пытаюсь вызвать функции. Думаю, это как-то связано с карри.

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)

person KCT    schedule 23.10.2014    source источник


Ответы (1)


Ваше 3. определение функции не является допустимым определением функции F#. Если вам нужно вызвать другую функцию «FreshConcreteLoad()», вы не можете использовать аннотации типов в вызове функции. Возможно, вы хотели привести параметры функции к единицам измерения, но это преобразование невозможно выполнить, поскольку единицы измерения F# не существуют в C#, поэтому значение 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])
person Petr    schedule 23.10.2014
comment
Большое спасибо. Это решение. Теперь мне просто нужно подумать о решении, которое быстрее, чем использование объекта Length из C#. использование double/float намного быстрее, но вы легко можете сделать ошибки, так как при использовании просто float‹m› в C# это просто double. Таким образом, порядок параметров и единица измерения могут быть неправильными. Любая идея или хорошо для другого вопроса? :) - person KCT; 23.10.2014
comment
Тяжело сказать. Возможно, используйте структуру на стороне C#. Length { public float value; public Unit uom /* И используйте enum как тип единицы измерения */ } - person Petr; 23.10.2014