2009-12-12 4 views
13

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

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

ответ

11

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

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

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

Я добавил IL. Бросьте из int, чтобы плавать, чтобы соответствовать этому вопросу. http://stackoverflow.com/a/21802111/17919 – gradbot

8

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

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

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

Unit-safe square roots

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

[<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 
+0

Будет ли что-то с этой подписью идти в библиотеку? Очевидно, что он будет доступен для записи с точки зрения запланированного FloatWithMeasure, но было бы лучше иметь функцию, которая явно безопасна в отдельности. –

+0

Этот ответ теперь дает предупреждение. «Этот тип теста или downcast будет игнорировать единицу измерения '' u '" – gradbot

4

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

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 ответ

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 
Смежные вопросы