F # Единица измерения, Кастинг без потери типа меры

Есть ли встроенная версия функций литья типа, которая сохраняет единицы, и если не так, как бы я их создал? Так, например, с помощью этого кода, как бы я передал intWithSecondsMeasure в float без потери меры или умножения на 1.0<s>?

[<Measure>] type s
let intWithSecondsMeasure = 1<s>
let justAFloat = float intWithSecondsMeasure 

Ответы

Ответ 1

Ответ, предоставленный @kvb, безусловно, работает, но я бы предпочел не использовать оператор unbox для этого преобразования. Там лучше, встроенный способ, который, по моему мнению, должен быть скомпилирован как NOP для IL (я не проверял, но unbox, вероятно, закончится как инструкция unbox в IL и, таким образом, добавит проверку типа времени выполнения).

Предпочтительным способом преобразования единиц в F # является LanguagePrimitives.TypeWithMeasure (MSDN).

let inline float32toFloat (x:float32<'u>) : float<'u> = 
    x |> float |> LanguagePrimitives.FloatWithMeasure

Ответ 2

Я не думаю, что есть встроенный способ сделать это, но вы можете легко определить свою собственную функцию преобразования единиц хранения:

let float_unit (x:int<'u>) : float<'u> = unbox float x
let floatWithSecondsMeasure = float_unit intWithSecondsMeasure

Ответ 3

Я скомпилировал код из ответов kvb и Johannes.

Йоханнес отвечает

let float32toFloat (x:int<'u>) : float<'u> = 
    x |> float |> LanguagePrimitives.FloatWithMeasure

.method public static float64  float32toFloat(int32 x) cil managed
{
  // Code size       3 (0x3)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  conv.r8
  IL_0002:  ret
} // end of method Program::float32toFloat

kvb ответ с добавленными скобками.

let float_unit (x:int<'u>) : float<'u> = unbox (float x)

.method public static float64  float_unit(int32 x) cil managed
{
  // Code size       13 (0xd)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  conv.r8
  IL_0002:  box        [mscorlib]System.Double
  IL_0007:  unbox.any  [mscorlib]System.Double
  IL_000c:  ret
} // end of method Program::float_unit

kvb answer

let float_unit (x:int<'u>) : float<'u> = unbox float x

.method public static float64  float_unit(int32 x) cil managed
{
  // Code size       19 (0x13)
  .maxstack  8
  IL_0000:  newobj     instance void Program/[email protected]::.ctor()
  IL_0005:  call       !!0 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/IntrinsicFunctions::UnboxGeneric<class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32,float64>>(object)
  IL_000a:  ldarg.0
  IL_000b:  tail.
  IL_000d:  callvirt   instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32,float64>::Invoke(!0)
  IL_0012:  ret
} // end of method Program::float_unit

Ответ 4

См. мой ответ на этот вопрос:

Единичные квадратные корни

который предлагает это сегодня:

[<Measure>] 
type s
let intWithSecondsMeasure = 1<s>

let intUtoFloatU< [<Measure>] 'u>( x : int<'u> ) : float<'u> = //'
    let i = int x       //  drop the units
    let f = float i     //  cast
    box f :?> float<'u> //' restore the units

let floatWithS = intUtoFloatU intWithSecondsMeasure