Unidades de medida (F#)
Flutuante ponto e os valores inteiros com sinal em F# pode ter associados unidades de medida, que geralmente são usadas para indicar o comprimento, volume, em massa, e assim por diante. Usando quantidades com unidades, você pode habilitar o compilador verificar se o relacionamento aritmético tem as unidades corretas, que ajuda a impedir 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 as unidades. Nas 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. Em 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 sendo 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 em conjunto com outras unidades, como no numerador. Por exemplo, as unidades para uma taxa seriam escritas como 1/s, onde s indica segundos. Parênteses não são usados em fórmulas de unidade. Você não especifica 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 no 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 em conjunto 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ê usa números de ponto flutuante sem rigidez de tipos. Se você escrever uma flutuante expressão de ponto que usa unidades, as unidades na expressão devem corresponder.
Você pode 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 do seu tipo primitivo (como float) em um tipo de dimensioned, como float<cm> ou, nesse caso, float<miles/hour>. Uma anotação de unidade de <1> indica uma quantidade não pode ser dimensionada e seu tipo é 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ê descreve 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, eles 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, ele 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 dimensioned. Você apenas multiplique por 1.0, aplicando as dimensões no 1.0. Você pode abstrair-isso em uma função como degreesFahrenheit.
Além disso, quando você passa valores de dimensioned às funções que esperam os números de ponto flutuante não pode ser dimensionado, você deve se cancelam as unidades ou convertido para float usando o float operador. Neste exemplo, divida por 1.0<degC> para os argumentos para printf porque printf não pode ser dimensionadas quantidades de espera.
[<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 associado. Fazer isso, especificando um tipo em conjunto 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
Criando tipos agregados com unidades genéricas
O código a seguir mostra como criar um tipo de agregação que consiste em individuais valores de ponto flutuante que possuem unidades que são genéricas. Isso permite que um único tipo a ser criado que 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, para que as unidades sejam perdidas em tempo de execução. Portanto, qualquer tentativa de implementar a funcionalidade que varia de acordo com as unidades a verificação em tempo de execução não é possível. Por exemplo, implementar um ToString a função para imprimir as unidades não é possível.
Conversões
Para converter um tipo que possui 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, conforme mostrado no código a seguir.
[<Measure>]
type cm
let length = 12.0<cm>
let x = float length
Para converter um valor sem unidade em 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, existem também algumas funções explícitas que pode ser usado 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.