サーチ…


備考

実行時のユニット

測定単位は、コンパイラによる静的検査にのみ使用され、実行時には使用できません。リフレクションやToStringようなメソッドでは使用できません。

たとえば、C#は、F#ライブラリによって定義され、 float<m>型のフィールドの単位を持たないdouble型をfloat<m>ます。

一貫性のある単位の計算を保証する

単位は浮動小数点数または整数に追加できる追加の型注釈です。コンパイル時に計算がユニットを一貫して使用しているかどうかを検証するために使用できます。

注釈を定義するには:

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

一旦定義されると、注釈を使用して、式が期待される型になることを検証することができます。

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

ユニット間のコンバージョン

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

F#コンパイラは、 1<m>100<cm>等しいことを知らないことに注意してください。それが気になる限り、ユニットは別々のタイプです。同様の関数を書いて、メートルからキログラムに変換することができます。コンパイラは気にしません。

[<Measure>] type kg

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

単位を他の単位の倍数として定義することはできません。

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

しかし、単位を「何か」に定義するには、周波数を測定するヘルツは単純に「毎秒」であり、非常に簡単です。

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

LanguagePrimitivesを使用してユニットを保存または設定する

関数が低レベル操作のためにユニットを自動的に保存しない場合、 LanguagePrimitivesモジュールを使用して、それらをサポートするプリミティブ上にユニットを設定することができます:

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

単位を倍精度浮動小数点値に割り当てるには、単純に正しい単位で1を掛けます。

[<Measure>]
type USD

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

単位をSystem.Double以外の単位のない値に割り当てるには(たとえば、別の言語で書かれたライブラリから到着する場合)、変換を使用します。

open LanguagePrimitives

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

F#インタラクティブによって報告された関数型は次のとおりです。

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

単位の種類のパラメータ

[<Measure>]属性は、タイプパラメータで使用して、メジャー単位で一般的な型を宣言することができます。

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

テスト使用法:

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

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

標準化されたユニットタイプを使用して互換性を維持する

たとえば、SI単位の型は、F#コアライブラリ、 Microsoft.FSharp.Data.UnitSystems.SI標準化されていMicrosoft.FSharp.Data.UnitSystems.SI 。適切なサブ名前空間、 UnitNamesまたはUnitSymbolsて使用します。 SI単位が必要な場合は、タイプエイリアスを使用してインポートできます。

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

一部のユーザーは次のことを行う傾向があります。定義がすでに利用可能な場合は、必ず実行しないください

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

この違いは、標準SIタイプを参照する他のコードとインタフェースするときに明らかになります。標準単位を参照するコードは互換性がありますが、独自の型を定義するコードは特定の定義を使用しないコードと互換性がありません。

したがって、SI単位には常に標準タイプを使用してください。 UnitNamesまたはUnitSymbolsを参照するかどうかは関係ありません。これらの2つの同等の名前は同じ型を参照するためです。

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
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow