2009-12-12 7 views
13

Esiste una versione incorporata delle funzioni di casting di tipo che preserva le unità e, in caso contrario, come faremmo? Quindi, ad esempio con questo codice, come potrei trasmettere intWithSecondsMeasure a un float senza perdere la misura o moltiplicando per 1.0<s>?F # Unità di misura, Casting senza perdere il tipo di misura

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

risposta

11

La risposta fornita da @kvb funziona sicuramente, ma preferirei non utilizzare l'operatore unbox per questa conversione. C'è un modo migliore, integrato nel mio I , pensare che debba essere compilato come NOP in IL (non ho controllato, ma unbox probabilmente finirà come un'istruzione unbox in IL e quindi aggiungerà un controllo di tipo runtime).

Il modo migliore per eseguire conversioni di unità in F # è LanguagePrimitives.TypeWithMeasure (MSDN).

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

Ho aggiunto l'IL. Trasmetti da int a float per essere coerente con la domanda. http://stackoverflow.com/a/21802111/17919 – gradbot

8

Non credo che ci sia un modo integrato di farlo, ma si può facilmente definire una funzione di conversione unità-preservando:

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

Vedere la mia risposta a questa domanda:

Unit-safe square roots

che suggerisce questo oggi:

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

Will qualcosa con questa firma andare in biblioteca? Ovviamente sarà scrivibile in termini di FloatWithMeasure pianificato, ma sarebbe più bello avere una funzione chiaramente disponibile per le unità direttamente disponibile. –

+0

Questa risposta ora dà un avvertimento. "Questo tipo di test o downcast ignorerà l'unità di misura '' u '" – gradbot

4

ho compilato il codice risposte KVB e Johannes.

Johannes rispondere

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 

risposta KVB con parentesi aggiunti.

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 risposta

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 
Problemi correlati