Мне нужно иметь возможность представлять одну и ту же концепцию несколькими разными единицами в F #.Например, я хочу изобразить «расстояние», используя световые годы, астрономические единицы, километры и метры.Я хотел бы использовать универсальную функцию для выполнения расчетов с этими значениями.Вот как я сгруппировал ly, AU, km и m вместе:
[<Measure>] type ly
[<Measure>] type AU
[<Measure>] type km
[<Measure>] type m
[<Measure>] type distance
type UnitValue<[<Measure>] 'u, [<Measure>] 't> =
val conversionFactor : float<'t / 'u>
val value : float<'u>
new (v, cf) = { value = FloatWithMeasure<'u> v; conversionFactor = FloatWithMeasure<'t / 'u> cf }
member this.toUnits = this.value * this.conversionFactor
member this.fromUnits (x : float<'t>) = x / this.conversionFactor
static member (+) (a : UnitValue<'u, 't>, b : UnitValue<_, 't>) =
a.newValue (a.toUnits + b.toUnits)
static member (-) (a : UnitValue<'u, 't>, b : UnitValue<_, 't>) =
a.newValue (a.toUnits - b.toUnits)
static member (*) (a : UnitValue<'u, 't>, b : float) =
a.newValue (a.toUnits * b)
member this.newValue (x : float<'t>) =
new UnitValue<'u, 't>(float (this.fromUnits x), float this.conversionFactor)
//Distance units
type LightYearValue(value) =
inherit UnitValue<ly, distance>(value, 6324.0)
type AstronomicalUnitValue(value) =
inherit UnitValue<AU, distance>(value, 15.0)
type KilometerValue(value) =
inherit UnitValue<km, distance>(value, 0.00001)
type MeterValue(value) =
inherit UnitValue<m, distance>(value, 0.0000000)
Этот код вызывается из C # -независимого кода, и это можно сделать, просто указав new LightYearValue(4.2)
, который станетUnitValue<ly, distance>
в F # и может быть передано функции, ожидающей UnitValue<_, distance>
.Таким образом, соответствующие единицы входят в функцию, а соответствующие единицы исчезают.Например, если я передал функцию UnitValue<AU, distance>
, я мог бы получить обратно float<AU / s ^ 2>
в зависимости от расчета - и это было бы подходящее число для шкалы.
Чувствуя себя довольно счастливым,Я начинаю писать тип орбиты:
and Orbit(PeR : UnitValue<_, distance>, ApR : UnitValue<_, distance>, AgP : float, focus : SphericalMass) =
let PeR = PeR
let ApR = ApR
let AgP = AgP
let focus = focus
let Maj = PeR + ApR
let Ecc = (Maj.value - (2.0 * PeR.value)) / Maj.value
let DistanceAt theta =
(Maj.value / 2.0) * (1.0 - Ecc ** 2.0) / (1.0 + Ecc * Math.Cos(theta))
, но когда я наводю указатель мыши на PeR
, он говорит, что его тип UnitValue<1, distance>
.Так что же дает?Почему это не работает?Я могу написать функцию, взяв UnitValue<_, distance>
, и она отлично работает!Может ли это быть связано с взаимодействием C # с этим кодом?(тип расширяется классом C #) Есть ли способ заставить эту работу: (