Buscar..


Observaciones

Unidades en tiempo de ejecución

Las unidades de medida se usan solo para la verificación estática por parte del compilador, y no están disponibles en tiempo de ejecución. No se pueden utilizar en la reflexión o en métodos como ToString .

Por ejemplo, C # da un double sin unidades para un campo de tipo float<m> definido y expuesto desde una biblioteca F #.

Asegurando Unidades Consistentes en Cálculos

Las unidades de medida son anotaciones de tipo adicionales que se pueden agregar a flotantes o enteros. Se pueden usar para verificar, en el momento de la compilación, que los cálculos utilizan unidades de manera consistente.

Para definir anotaciones:

[<Measure>] type m // meters
[<Measure>] type s // seconds
[<Measure>] type accel = m/s^2 // acceleration defined as meters per second squared

Una vez definidas, las anotaciones se pueden usar para verificar que una expresión dé como resultado el tipo esperado.

// Compile-time checking that this function will return meters, since (m/s^2) * (s^2) -> m
// Therefore we know units were used properly in the calculation.
let freeFallDistance (time:float<s>) : float<m> = 
    0.5 * 9.8<accel> * (time*time)    

// It is also made explicit at the call site, so we know that the parameter passed should be in seconds
let dist:float<m> = freeFallDistance 3.0<s>
printfn "%f" dist

Conversiones entre unidades

[<Measure>] type m // meters
[<Measure>] type cm // centimeters

// Conversion factor
let cmInM = 100<cm/m>

let distanceInM = 1<m>
let distanceInCM = distanceInM * cmInM // 100<cm>

// Conversion function
let cmToM (x : int<cm>) = x / 100<cm/m>
let mToCm (x : int<m>) = x * 100<cm/m>

cmToM 100<cm> // 1<m>
mToCm 1<m> // 100<cm>

Tenga en cuenta que el compilador F # no sabe que 1<m> es igual a 100<cm> . En cuanto a lo que importa, las unidades son tipos separados. Puede escribir funciones similares para convertir de metros a kilogramos, y al compilador no le importará.

[<Measure>] type kg

// Valid code, invalid physics
let kgToM x = x / 100<kg/m>

No es posible definir unidades de medida como múltiplos de otras unidades como

// Invalid code
[<Measure>] type m = 100<cm>

Sin embargo, definir unidades "por algo", por ejemplo Hertz, medir la frecuencia, es simplemente "por segundo", es bastante simple.

// Valid code
[<Measure>] type s
[<Measure>] type Hz = /s

1 / 1<s> = 1 <Hz> // Evaluates to true

[<Measure>] type N = kg m/s // Newtons, measuring force. Note lack of multiplication sign.

// Usage
let mass = 1<kg>
let distance = 1<m>
let time = 1<s>

let force = mass * distance / time // Evaluates to 1<kg m/s>
force = 1<N> // Evaluates to true

Usando LanguagePrimitives para preservar o establecer unidades

Cuando una función no conserva las unidades automáticamente debido a las operaciones de nivel inferior, el módulo LanguagePrimitives se puede usar para establecer unidades en las primitivas que las soportan:

/// This cast preserves units, while changing the underlying type
let inline castDoubleToSingle (x : float<'u>) : float32<'u> =
    LanguagePrimitives.Float32WithMeasure (float32 x)

Para asignar unidades de medida a un valor de punto flotante de precisión doble, simplemente multiplique por uno con las unidades correctas:

[<Measure>]
type USD

let toMoneyImprecise (amount : float) =
   amount * 1.<USD>

Para asignar unidades de medida a un valor sin unidades que no sea Sistema. Doble, por ejemplo, al llegar de una biblioteca escrita en otro idioma, use una conversión:

open LanguagePrimitives

let toMoney amount =
   amount |> DecimalWithMeasure<'u>

Aquí están los tipos de funciones reportadas por F # interactivo:

val toMoney : amount:decimal -> decimal<'u>
val toMoneyImprecise : amount:float -> float<USD>

Parámetros del tipo de unidad de medida

El atributo [<Measure>] se puede usar en los parámetros de tipo para declarar tipos que son genéricos con respecto a las unidades de medida:

type CylinderSize<[<Measure>] 'u> =
    { Radius : float<'u>
      Height : float<'u> }

Uso de prueba:

open Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols

/// This has type CylinderSize<m>.
let testCylinder =
    { Radius = 14.<m>
      Height =  1.<m> }

Usa tipos de unidades estandarizadas para mantener la compatibilidad

Por ejemplo, los tipos para las unidades SI se han estandarizado en la biblioteca central F #, en Microsoft.FSharp.Data.UnitSystems.SI . Abra el UnitNames apropiado, UnitNames o UnitSymbols , para usarlos. O, si solo se requieren unas pocas unidades SI, se pueden importar con alias de tipo:

/// Seconds, the SI unit of time. Type abbreviation for the Microsoft standardized type.
type [<Measure>] s = Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols.s

Algunos usuarios tienden a hacer lo siguiente, que no debe hacerse cuando ya hay una definición disponible:

/// Seconds, the SI unit of time
type [<Measure>] s // DO NOT DO THIS! THIS IS AN EXAMPLE TO EXPLAIN A PROBLEM.

La diferencia se hace evidente al interactuar con otro código que se refiere a los tipos de SI estándar. El código que hace referencia a las unidades estándar es compatible, mientras que el código que define su propio tipo es incompatible con cualquier código que no utilice su definición específica.

Por lo tanto, siempre use los tipos estándar para las unidades SI. No importa si hace referencia a UnitNames o UnitSymbols , ya que los nombres equivalentes dentro de esos dos se refieren al mismo tipo:

open Microsoft.FSharp.Data.UnitSystems.SI

/// This is valid, since both versions refer to the same authoritative type.
let validSubtraction = 1.<UnitSymbols.s> - 0.5<UnitNames.second>


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow