Satuan Ukuran

Bilangan titik mengambang dan bilangan bulat bertanda dalam F# dapat memiliki satuan ukuran terkait, yang biasanya digunakan untuk menunjukkan panjang, volume, massa, dan sebagainya. Dengan menggunakan jumlah dengan unit, Anda memungkinkan penyusun untuk memverifikasi bahwa hubungan aritmatika memiliki unit yang benar, sehingga membantu mencegah kesalahan pemrograman.

Catatan

Contoh-contoh ini menunjukkan kebenaran dalam komputasi aritmatika yang melibatkan satuan ukuran, fitur ini juga dapat dimanfaatkan untuk menambahkan anotasi aman jenis dengan biaya representasi nol ke jenis lain, dengan pendekatan seperti proyek FSharp.UMX .

Sintaks

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

Keterangan

Sintaks sebelumnya mendefinisikan nama satuan sebagai satuan pengukuran. Bagian opsional digunakan untuk menentukan ukuran baru dalam hal satuan yang ditentukan sebelumnya. Misalnya, baris berikut menentukan ukuran cm (sentimeter).

[<Measure>] type cm

Baris berikut mendefinisikan ukuran ml (mililiter) dalam sentimeter kubik (cm^3).

[<Measure>] type ml = cm^3

Dalam sintaks sebelumnya, pengukuran adalah rumus yang melibatkan satuan. Dalam rumus yang melibatkan satuan, daya integral didukung (positif dan negatif), spasi antar satuan menunjukkan produk dari dua satuan, * juga menunjukkan produk satuan, dan / menunjukkan kuota satuan. Untuk unit timbal balik, Anda dapat menggunakan daya bilangan bulat negatif atau / yang menunjukkan pemisahan antara pembilang dan penyebut pada rumus satuan. Beberapa unit dalam penyebut harus diberi tanda kurung. Satuan yang dipisahkan oleh spasi setelah / ditafsirkan sebagai bagian dari penyebut, tetapi satuan apa pun yang mengikuti ditafsirkan * sebagai bagian dari pembilang.

Anda dapat menggunakan 1 dalam ekspresi satuan, baik sendiri untuk menunjukkan kuantitas tanpa dimensi, atau bersama dengan satuan lain, seperti di pembilang. Misalnya, satuan untuk laju akan ditulis sebagai 1/s, dan s menunjukkan detik. Tanda kurung tidak digunakan dalam rumus satuan. Anda tidak menentukan konstanta konversi numerik dalam rumus satuan; namun, Anda dapat menentukan konstanta konversi dengan satuan secara terpisah dan menggunakannya dalam perhitungan yang diperiksa satuan.

Rumus satuan artinya hal yang sama dapat ditulis dengan berbagai cara yang setara. Oleh karena itu, penyusun mengubah rumus satuan menjadi bentuk yang konsisten, yang daya kekuatan negatif menjadi timbal balik, mengelompokkan satuan menjadi pembilang tunggal dan penyebut, dan menjadikan satuan alfabet dalam pembilang dan penyebut.

Misalnya, rumus satuan kg m s^-2 dan m /s s * kg keduanya dikonversi ke kg m/s^2.

Gunakan satuan ukuran dalam ekspresi bilangan titik mengambang. Menggunakan bilangan titik mengambang bersama dengan satuan pengukuran terkait akan menambah tingkat keamanan jenis lain dan membantu menghindari kesalahan ketidakcocokan satuan yang dapat terjadi dalam rumus saat Anda menggunakan bilangan titik mengambang yang dikonversi secara implisit. Jika Anda menulis ekspresi bilangan titik mengambang yang menggunakan satuan, satuan dalam ekspresi tersebut harus cocok.

Anda dapat membuat anotasi harfiah dengan rumus satuan dalam tanda kurung sudut, seperti yang ditunjukkan pada contoh berikut.

1.0<cm>
55.0<miles/hour>

Jangan meletakkan spasi antara angka dan kurung sudut; namun, Anda dapat menyertakan akhiran harfiah contohnya f, seperti dalam contoh berikut.

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

Anotasi semacam itu mengubah jenis harfiah dari jenis primitifnya (seperti float) menjadi jenis dimensi, seperti float<cm> atau, dalam hal ini, float<miles/hour>. Anotasi satuan <1> menunjukkan kuantitas tanpa dimensi, dan jenisnya setara dengan jenis primitif tanpa parameter satuan.

Jenis satuan pengukuran adalah bilangan titik mengambang atau jenis bilangan bulat bertanda bersama dengan anotasi satuan tambahan, yang ditunjukkan dalam tanda kurung. Dengan demikian, saat Anda menulis jenis konversi dari g (gram) ke kg (kilogram), dekripsikan jenisnya sebagai berikut.

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

Satuan pengukuran digunakan untuk pemeriksaan satuan waktu kompilasi tetapi tidak bertahan di lingkungan run-time. Oleh karena itu, satuan pengukuran tidak mempengaruhi performa.

Satuan ukuran dapat diterapkan pada jenis apa pun, bukan hanya jenis bilangan titik mengambang; namun, hanya jenis bilangan titik mengambang, jenis bilangan bulat bertanda, dan jenis desimal yang mendukung jumlah berdimensi. Oleh karena itu, masuk akal untuk menggunakan satuan ukuran pada jenis primitif dan agregat yang mengandung jenis primitif ini.

Contoh berikut menggambarkan penggunaan satuan ukuran.

// 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^2

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

Contoh kode berikut mengilustrasikan cara mengonversi dari bilangan titik mengambang tanpa dimensi ke bilangan titik mengambang berdimensi. Anda hanya mengalikan dengan 1.0, sehingga menerapkan dimensi ke 1.0. Anda dapat mengabstraksikan nilai ini ke dalam fungsi seperti degreesFahrenheit.

Selain itu, ketika Anda meneruskan nilai dimensi ke fungsi yang mengharapkan bilangan titik mengambang tanpa dimensi, Anda harus membatalkan unit atau transmisi ke float dengan menggunakan operator float. Dalam contoh ini, Anda membagi dengan 1.0<degC> untuk argumen ke printf karena printf mengharapkan jumlah tanpa dimensi.

[<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 parsedOk, floatValue = System.Double.TryParse(input)
if parsedOk
   then
      printfn "That temperature in Celsius is %8.2f degrees C." ((convertFtoC (degreesFahrenheit floatValue))/(1.0<degC>))
   else
      printfn "Error parsing input."

Sesi contoh berikut menunjukkan output dan input kode ini.

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

Jenis Primitif yang mendukung Satuan Pengukuran

Jenis atau alias dari jenis singkatan berikut mendukung anotasi satuan pengukuran:

Alias F# Jenis CLR
float32/single System.Single
float/double System.Double
decimal System.Decimal
sbyte/int8 System.SByte
int16 System.Int16
int/int32 System.Int32
int64 System.Int64
byte/uint8 System.Byte
uint16 System.UInt16
uint/uint32 System.UInt32
uint64 System.UIn64
nativeint System.IntPtr
unativeint System.UIntPtr

Misalnya, Anda dapat membuat anotasi bilangan bulat tidak bertanda sebagai berikut:

[<Measure>]
type days

let better_age = 3u<days>

Penambahan jenis bilangan bulat tidak bertanda pada fitur ini didokumentasikan dalam F# RFC FS-1091.

Satuan Ukuran yang Telah Ditentukan Sebelumnya

Pustaka satuan tersedia di namespace layanan FSharp.Data.UnitSystems.SI. Termasuk unit SI dalam bentuk simbol mereka (seperti m untuk meter) di sub-namespace UnitSymbols, dan dalam nama lengkapnya (seperti meter untuk meter) di sub-namespace UnitNames.

Menggunakan Satuan Generik

Anda dapat menulis fungsi generik yang beroperasi pada data yang memiliki satuan ukuran terkait. Tulislah dengan menentukan jenis bersama dengan satuan generik sebagai parameter jenis, seperti yang ditunjukkan pada contoh kode berikut.

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

Membuat Jenis Kumpulan dengan Satuan Generik

Kode berikut menunjukkan cara membuat jenis agregat yang terdiri dari nilai bilangan titik mengambang individual yang memiliki satuan generik. Hal ini memungkinkan pembuatan jenis tunggal yang bekerja dengan berbagai satuan. Selain itu, satuan generik menjaga keamanan jenis dengan memastikan bahwa jenis generik yang memiliki satu set satuan adalah jenis yang berbeda dari jenis generik yang sama dengan satu set satuan yang berbeda. Dasar dari teknik ini adalah bahwa atribut Measure dapat diterapkan ke parameter jenis.

 // 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> }

Satuan saat Runtime

Satuan ukuran digunakan untuk pemeriksaan jenis statis. Ketika nilai bilangan titik mengambang dikompilasi, satuan ukuran dihilangkan, sehingga satuan hilang pada runtime. Oleh karena itu, setiap upaya untuk menerapkan fungsionalitas yang bergantung pada pemeriksaan satuan saat runtime tidak mungkin dilakukan. Misalnya, menerapkan fungsi ToString untuk mencetak satuan tidak dimungkinkan.

Konversi

Untuk mengonversi jenis yang memiliki satuan (misalnya, float<'u>) ke jenis yang tidak memiliki satuan, Anda dapat menggunakan fungsi konversi standar. Misalnya, Anda dapat menggunakan float untuk mengonversi ke nilai float yang tidak memiliki satuan, seperti yang ditunjukkan dalam kode berikut.

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

Untuk mengonversi nilai tanpa satuan menjadi nilai yang memiliki satuan, Anda dapat mengalikan dengan nilai 1 atau 1,0 yang dianotasi dengan satuan yang sesuai. Namun, untuk menulis lapisan interoperabilitas, ada juga beberapa fungsi eksplisit yang dapat Anda gunakan untuk mengonversi nilai tanpa satuan menjadi nilai dengan satuan. Terdapat di modul FSharp.Core.LanguagePrimitives. Misalnya, untuk mengonversi dari float tanpa satuan ke float<cm>, gunakan FloatWithMeasure, seperti yang ditunjukkan dalam kode berikut.

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

Lihat juga