Unidades de medida (F#)

Flutuante ponto e os valores inteiros com sinal de F# pode ter associados unidades de medida, que geralmente são usadas para indicar o comprimento, volume, em massa, e assim por diante. Usando as quantidades com unidades, você habilitar o compilador verificar se o relacionamento aritmético tem unidades corretas, que ajuda a evitar erros de programação.

[<Measure>] type unit-name [ = measure ]

Comentários

A sintaxe anterior define unit-name como uma unidade de medida. A parte opcional é usada para definir uma nova medida em termos de unidades definidas anteriormente. Por exemplo, a linha a seguir define a medida cm (centímetro).

[<Measure>] type cm

A linha a seguir define a medida ml (milliliter) como um centímetro cúbico (cm^3).

[<Measure>] type ml = cm^3

Na sintaxe anterior, measure é uma fórmula que envolve unidades. Em fórmulas que envolvem as unidades, potências integrais são suportadas (positivo e negativo), espaços entre as unidades indicam um produto de duas unidades, * também indica um produto de unidades, e / indica um quociente de unidades. Para uma unidade recíproca, você pode usar uma potência de número inteiro negativo ou um / que indica uma separação entre o numerador e denominador de uma fórmula de unidade. Várias unidades no denominador devem estar entre parênteses. Unidades separadas por espaços após um / são interpretados como parte do denominador, mas quaisquer unidades seguindo uma * são interpretados como parte do numerador.

Você pode usar 1 em expressões de unidade, sozinho para indicar uma quantidade não pode ser dimensionada, ou junto com outras unidades, como no numerador. Por exemplo, as unidades para uma taxa seriam escritas como 1/s, onde s indica segundos. Não, os parênteses são usados em fórmulas de unidade. Você não especificar constantes de conversão numérica nas fórmulas de unidade; No entanto, você pode definir constantes de conversão com unidades separadamente e usá-los em computações verificado por unidade.

Fórmulas de unidade que tem o mesmo significado podem ser gravadas de várias maneiras equivalentes. Portanto, o compilador converte as fórmulas de unidade em uma forma consistente, que converte o potências negativas recíprocos, unidades de grupos em um único numerador e um denominador e coloca em ordem alfabética as unidades do numerador e denominador.

Por exemplo, as fórmulas de unidade kg m s^-2 e m /s s * kg são convertidas em kg m/s^2.

Você pode usar unidades de medida em expressões de ponto flutuante. O uso de números de ponto flutuante juntamente com as unidades associadas de medida adiciona outro nível de segurança de tipos e ajuda a evitar os erros de incompatibilidade de unidade que podem ocorrer em fórmulas quando você usar números de ponto flutuante sem rigidez de tipos. Se você escrever uma flutuante expressão de ponto usa unidades, as unidades na expressão devem corresponder.

Você poderá anotar literais com uma fórmula de unidade em colchetes angulares, conforme mostrado nos exemplos a seguir.

1.0<cm>
55.0<miles/hour>

Você não coloque um espaço entre o número e o colchete angular; No entanto, você pode incluir um sufixo literal, como f, como no exemplo a seguir.

// The f indicates single-precision floating point.
55.0f<miles/hour> 

Como uma anotação altera o tipo do literal de seu tipo primitivo (como float) para um tipo de dimensioned, como float<cm> ou, nesse caso, float<miles/hour>. Uma anotação de unidade de <1> indica o tipo e a quantidade não pode ser dimensionada, é equivalente ao tipo primitivo sem um parâmetro de unidade.

O tipo de uma unidade de medida é um ponto flutuante ou assinado tipo integral, juntamente com uma anotação de unidade extra, indicada entre parênteses. Assim, quando você escreve o tipo de uma conversão de g (gramas) para kg (quilos), você descrever os tipos, como segue:

let convertg2kg (x : float<g>) = x / 1000.0<g/kg>

Unidades de medida são usadas para verificação de unidade de tempo de compilação, mas não são persistentes no ambiente de tempo de execução. Portanto, elas não afetam o desempenho.

Unidades de medida podem ser aplicadas a qualquer tipo, flutuante não apenas os tipos de ponto; No entanto, somente tipos de ponto flutuante, assinado tipos integrais e quantidades de suporte dimensionada de tipos de decimal. Portanto, só faz sentido usar unidades de medida, os tipos primitivos e agregados que contêm esses tipos primitivos.

O exemplo a seguir ilustra o uso de unidades de medida.

// Mass, grams.
[<Measure>] type g
// Mass, kilograms.
[<Measure>] type kg
// Weight, pounds.
[<Measure>] type lb 

// Distance, meters. 
[<Measure>] type m
// Distance, cm
[<Measure>] type cm

// Distance, inches.
[<Measure>] type inch
// Distance, feet
[<Measure>] type ft

// Time, seconds.
[<Measure>] type s

// Force, Newtons.
[<Measure>] type N = kg m / s 

// Pressure, bar.
[<Measure>] type bar 
// Pressure, Pascals
[<Measure>] type Pa = N / m^2 

// Volume, milliliters.
[<Measure>] type ml 
// Volume, liters.
[<Measure>] type L

// Define conversion constants.
let gramsPerKilogram : float<g kg^-1> = 1000.0<g/kg>
let cmPerMeter : float<cm/m> = 100.0<cm/m>
let cmPerInch : float<cm/inch> = 2.54<cm/inch>

let mlPerCubicCentimeter : float<ml/cm^3> = 1.0<ml/cm^3>
let mlPerLiter : float<ml/L> = 1000.0<ml/L>

// Define conversion functions.
let convertGramsToKilograms (x : float<g>) = x / gramsPerKilogram
let convertCentimetersToInches (x : float<cm>) = x / cmPerInch

O exemplo de código a seguir ilustra como converter de um número de ponto flutuante não pode ser dimensionado para um valor de ponto flutuante de dimensioned. Você apenas multiplicar pelo 1.0, aplicando as dimensões no 1.0. Isso pode ser abstract em uma função como degreesFahrenheit.

Além disso, quando você passar valores dimensioned às funções que esperam que os números de ponto flutuante não pode ser dimensionado, você deve cancelar a unidades ou converter para float usando o float operador. Neste exemplo, divida por 1.0<degC> para os argumentos para printf porque printf espera não pode ser dimensionado quantidades.

[<Measure>] type degC // temperature, Celsius/Centigrade
[<Measure>] type degF // temperature, Fahrenheit

let convertCtoF ( temp : float<degC> ) = 9.0<degF> / 5.0<degC> * temp + 32.0<degF>
let convertFtoC ( temp: float<degF> ) = 5.0<degC> / 9.0<degF> * ( temp - 32.0<degF>)

// Define conversion functions from dimensionless floating point values.
let degreesFahrenheit temp = temp * 1.0<degF>
let degreesCelsius temp = temp * 1.0<degC>

printfn "Enter a temperature in degrees Fahrenheit."
let input = System.Console.ReadLine()
let mutable floatValue = 0.
if System.Double.TryParse(input, &floatValue)
   then 
      printfn "That temperature in Celsius is %8.2f degrees C." ((convertFtoC (degreesFahrenheit floatValue))/(1.0<degC>))
   else
      printfn "Error parsing input."

A sessão de exemplo a seguir mostra as entradas para esse código e saídas de.

Enter a temperature in degrees Fahrenheit.
90
That temperature in degrees Celsius is    32.22.

Usando unidades genéricas

Você pode escrever funções genéricas que operam em dados que possui uma unidade de medida de associados. Fazer isso, especificando um tipo juntamente com uma unidade genérico como um parâmetro de tipo, conforme mostrado no exemplo de código a seguir.

// Distance, meters. 
[<Measure>] type m 
// Time, seconds. 
[<Measure>] type s

let genericSumUnits ( x : float<'u>) (y: float<'u>) = x + y

let v1 = 3.1<m/s>
let v2 = 2.7<m/s>
let x1 = 1.2<m>
let t1 = 1.0<s>

// OK: a function that has unit consistency checking.
let result1 = genericSumUnits v1 v2
// Error reported: mismatched units.
// Uncomment to see error.
// let result2 = genericSumUnits v1 x1

A criação de tipos de agregação com unidades genéricas

O código a seguir mostra como criar um tipo de agregação consiste individuais valores de ponto flutuante que possuem unidades que são genéricas. Isso permite que um único tipo a ser criado funciona com uma variedade de unidades. Além disso, unidades genéricas preservam a segurança de tipos, garantindo que um tipo genérico que tem um conjunto de unidades é um tipo diferente do mesmo tipo genérico com um conjunto diferente de unidades. A base dessa técnica é que o Measure atributo pode ser aplicado para o parâmetro de tipo.

 // Distance, meters.
[<Measure>] type m 
// Time, seconds. 
[<Measure>] type s 

// Define a vector together with a measure type parameter.
// Note the attribute applied to the type parameter.
type vector3D<[<Measure>] 'u> = { x : float<'u>; y : float<'u>; z : float<'u>}

// Create instances that have two different measures.
// Create a position vector.
let xvec : vector3D<m> = { x = 0.0<m>; y = 0.0<m>; z = 0.0<m> }
// Create a velocity vector.
let v1vec : vector3D<m/s> = { x = 1.0<m/s>; y = -1.0<m/s>; z = 0.0<m/s> }

Unidades em tempo de execução

Unidades de medida são usadas para verificação de tipo estático. Quando valores de ponto flutuante são compiladas, as unidades de medida são eliminadas, portanto, as unidades são perdidas em tempo de execução. Portanto, qualquer tentativa de implementar a funcionalidade que varia de acordo com as unidades de verificação em tempo de execução não é possível. Por exemplo, implementar um ToString a função para imprimir as unidades é possível.

Conversões

Para converter um tipo de unidades (por exemplo, float<'u>) para um tipo que não possui unidades, você pode usar a função de conversão padrão. Por exemplo, você pode usar float para converter em um float valor que não possui unidades, como mostra o código a seguir.

[<Measure>]
type cm
let length = 12.0<cm>
let x = float length

Para converter um valor sem unidade para um valor de unidades, é possível multiplicar por um valor de 1 ou 1.0 é anotado com as unidades adequadas. No entanto, para escrever as camadas de interoperabilidade, há também algumas funções explícitas que você pode usar para converter valores sem unidade para valores com unidades. Essas opções estão na Microsoft.FSharp.Core.LanguagePrimitives module. Por exemplo, para converter de um sem unidade float para um float<cm>, use FloatWithMeasure, conforme mostrado no código a seguir.

open Microsoft.FSharp.Core
let height:float<cm> = LanguagePrimitives.FloatWithMeasure x

Unidades de medida no pacote de F# energia

Uma biblioteca de unidade está disponível o PowerPack F#. A biblioteca de unidade inclui unidades de SI e constantes físicas.

Consulte também

Outros recursos

Referência de linguagem do F#

Histórico de alterações

Date

History

Motivo

Maio de 2010

Corrija o exemplo de código na seção de conversões.

Correção de bug de conteúdo.