静的に解決される型パラメーター
"静的に解決される型パラメーター" とは、実行時でなく、コンパイル時に実際の型に置き換えられる型パラメーターです。
構文
'type-parameter
F# のバージョン 7.0 までは、次の構文を使用する必要がありました
^type-parameter
解説
F# には、異なる 2 種類の型パラメーターがあります。 1 つ目の種類は、標準のジェネリック型パラメーターです。 これらは、その他の .NET 言語のジェネリック型パラメーターと同じです。 もう 1 つの種類は静的に解決され、インライン関数でのみ使用できます。
静的に解決される型パラメーターは、主にメンバー制約で使用する場合に役立ちます。これは、型引数を使用するために特定のメンバーが必要であることを指定できる制約です。 この種の制約を、標準のジェネリック型パラメーターを使用して作成する方法はありません。
2 種類の型パラメーターの類似点と相違点の概要を次の表に示します。
機能 | ジェネリック | 静的に解決される |
---|---|---|
解決時期 | 実行時 | コンパイル時間 |
メンバー制約 | メンバー制約では使用できません。 | メンバー制約で使用できます。 |
コード生成 | 標準のジェネリック型パラメーターを持つ型 (またはメソッド) では、単一のジェネリック型またはジェネリック メソッドが生成されます。 | 各型で必要とされる、型およびメソッドの複数のインスタンス化が生成されます。 |
型での使用 | 型で使用できます。 | 型では使用できません。 |
インライン関数での使用 | 標準のジェネリック型パラメーターではインライン関数をパラメーター化できません。 入力が完全にジェネリックでない場合は、F# コンパイラによって特殊化されるか、特殊化するオプションがない場合はエラーが発生します。 | 静的に解決される型パラメーターは、インライン以外の関数またはメソッドでは使用できません。 |
多数の F# コア ライブラリ関数 (特に演算子) には、静的に解決される型パラメーターがあります。 これらの関数および演算子はインラインであり、数値の計算に効率的なコードが生成されます。
演算子を使用するインライン メソッドおよび関数、または静的に解決される型パラメーターを持つ他の関数を使用するインライン メソッドおよび関数では、それらのメソッドおよび関数自体でも静的に解決される型パラメーターを使用できます。 多くの場合、型推論では、それらのインライン関数が静的に解決される型パラメーターを持つと推論されます。 静的に解決される型パラメーターを持つと推論される演算子の定義を次の例に示します。
let inline (+@) x y = x + x * y
// Call that uses int.
printfn "%d" (1 +@ 1)
// Call that uses float.
printfn "%f" (1.0 +@ 0.5)
解決された (+@)
の型は、(+)
および (*)
の使用に基づいており、これらの両方では型推論によって、静的に解決される型パラメーターによるメンバー制約が推論されます。 F# インタープリターに表示される解決された型は、次のとおりです。
'a -> 'c -> 'd
when ('a or 'b) : (static member ( + ) : 'a * 'b -> 'd) and
('a or 'c) : (static member ( * ) : 'a * 'c -> 'b)
出力は次のとおりです。
2
1.500000
次の例は、SRTP とメソッドの使用方法と静的メソッドを示しています。
type Record =
{ Number: int }
member this.Double() = { Number = this.Number * 2 }
static member Zero() = { Number = 0 }
let inline double<'a when 'a:(member Double: unit -> 'a)> (x: 'a) = x.Double()
let inline zero<'a when 'a:(static member Zero: unit -> 'a)> () = 'a.Zero()
let r: Record = zero ()
let doubleR = double r
F# 7.0 以降では、次の例のように制約を繰り返す代わりに 'a.Zero()
を使用できます。
F# 4.1 以降では、静的に解決される型パラメーター シグネチャに具象型名を指定することもできます。 以前のバージョンの言語では、型名はコンパイラで推論されましたが、シグネチャに指定することはできませんでした。 F# 4.1 以降は、静的に解決される型パラメーター シグネチャに具象型名を指定することもできます。 以下に例を示します ('
を使用した単純化はサポートされていないため、この例では引き続き ^
を使用する必要があることに注意してください)。
let inline konst x _ = x
type CFunctor() =
static member inline fmap (f: ^a -> ^b, a: ^a list) = List.map f a
static member inline fmap (f: ^a -> ^b, a: ^a option) =
match a with
| None -> None
| Some x -> Some (f x)
// default implementation of replace
static member inline replace< ^a, ^b, ^c, ^d, ^e when ^a :> CFunctor and (^a or ^d): (static member fmap: (^b -> ^c) * ^d -> ^e) > (a, f) =
((^a or ^d) : (static member fmap : (^b -> ^c) * ^d -> ^e) (konst a, f))
// call overridden replace if present
static member inline replace< ^a, ^b, ^c when ^b: (static member replace: ^a * ^b -> ^c)>(a: ^a, f: ^b) =
(^b : (static member replace: ^a * ^b -> ^c) (a, f))
let inline replace_instance< ^a, ^b, ^c, ^d when (^a or ^c): (static member replace: ^b * ^c -> ^d)> (a: ^b, f: ^c) =
((^a or ^c): (static member replace: ^b * ^c -> ^d) (a, f))
// Note the concrete type 'CFunctor' specified in the signature
let inline replace (a: ^a) (f: ^b): ^a0 when (CFunctor or ^b): (static member replace: ^a * ^b -> ^a0) =
replace_instance<CFunctor, _, _, _> (a, f)
関連項目
.NET