自動ジェネリック化Automatic Generalization

F#関数と式の型を評価する推論を使用してに入力します。F# uses type inference to evaluate the types of functions and expressions. このトピックでは、どの F# 自動的に一般化引数と関数の種類可能な限り、複数の種類で動作させることについて説明します。This topic describes how F# automatically generalizes the arguments and types of functions so that they work with multiple types when this is possible.

自動ジェネリック化Automatic Generalization

F#関数の型の推定の実行時に、コンパイラは、指定されたパラメーターをジェネリックにできるかどうかを決定します。The F# compiler, when it performs type inference on a function, determines whether a given parameter can be generic. コンパイラは、各パラメーターを調べ、関数は、そのパラメーターの特定の種類に依存しているかどうかを決定します。The compiler examines each parameter and determines whether the function has a dependency on the specific type of that parameter. そうでない場合をジェネリック型が推論されます。If it does not, the type is inferred to be generic.

次のコード例では、ジェネリックと、コンパイラが推論される関数を示しています。The following code example illustrates a function that the compiler infers to be generic.

let max a b = if a > b then a else b

型が推論'a -> 'a -> 'aします。The type is inferred to be 'a -> 'a -> 'a.

種類は、同じの不明な型の 2 つの引数を受け取り、その同じ型の値を返します関数であることを示します。The type indicates that this is a function that takes two arguments of the same unknown type and returns a value of that same type. 前の関数ができる理由の 1 つジェネリックは、大きい-演算子よりも (>) 自体が、ジェネリック。One of the reasons that the previous function can be generic is that the greater-than operator (>) is itself generic. 大きい-より演算子がある署名'a -> 'a -> boolします。The greater-than operator has the signature 'a -> 'a -> bool. すべての演算子は、ジェネリックとそのパラメーターの型を一般化することはできません、関数のコードは、非ジェネリック関数または演算子とパラメーターの型を使用している場合。Not all operators are generic, and if the code in a function uses a parameter type together with a non-generic function or operator, that parameter type cannot be generalized.

maxは汎用的で、これで使える型などintfloatこれに、次の例に示すようにします。Because max is generic, it can be used with types such as int, float, and so on, as shown in the following examples.

let biggestFloat = max 2.0 3.0
let biggestInt = max 2 3

ただし、同じ型の 2 つの引数がある必要があります。However, the two arguments must be of the same type. 署名が'a -> 'a -> 'aではなく、'a -> 'b -> 'aします。The signature is 'a -> 'a -> 'a, not 'a -> 'b -> 'a. そのため、次のコードは、型が一致しないため、エラーを生成します。Therefore, the following code produces an error because the types do not match.

// Error: type mismatch.
let biggestIntFloat = max 2.0 3

max関数でも使用できますか大きい方をサポートする任意の型の演算子よりもします。The max function also works with any type that supports the greater-than operator. そのためも使用できますが、文字列の次のコードに示すようにします。Therefore, you could also use it on a string, as shown in the following code.

let testString = max "cab" "cat"

値の制限Value Restriction

コンパイラは、不変の単純な値で明示的な引数を持つ完全な関数定義でのみ自動ジェネリック化を実行します。The compiler performs automatic generalization only on complete function definitions that have explicit arguments, and on simple immutable values.

これは、十分には、特定の型にするのには制限されませんが、汎化可能ながもコードをコンパイルしようとする場合、コンパイラがエラーを発行することを意味します。This means that the compiler issues an error if you try to compile code that is not sufficiently constrained to be a specific type, but is also not generalizable. この問題のエラー メッセージがこの制約として値の自動ジェネリック化を参照、値制限します。The error message for this problem refers to this restriction on automatic generalization for values as the value restriction.

通常、構成要素は、ジェネリックしたいが、コンパイラが不十分な情報を一般化し、ときに、または意図せずに、非ジェネリック コンストラクトに十分な情報を入力を省略すると、値制限エラーが発生します。Typically, the value restriction error occurs either when you want a construct to be generic but the compiler has insufficient information to generalize it, or when you unintentionally omit sufficient type information in a nongeneric construct. 値制限エラーの解決策より完全で、次の方法のいずれかの型の推論の問題は制約より明確な情報を提供することです。The solution to the value restriction error is to provide more explicit information to more fully constrain the type inference problem, in one of the following ways:

  • 値またはパラメーターに明示的な型注釈の追加、非ジェネリックの型を制限します。Constrain a type to be nongeneric by adding an explicit type annotation to a value or parameter.

  • 問題は、関数の合成などの汎用関数を定義する汎化できない構成要素を使用して、または不完全カリー化された関数の引数に適用は、通常の関数定義として関数を書き直してください。 お試しください。If the problem is using a nongeneralizable construct to define a generic function, such as a function composition or incompletely applied curried function arguments, try to rewrite the function as an ordinary function definition.

  • 問題が複雑すぎるために一般化する式の場合は、ように関数に、未使用のパラメーターを追加することで。If the problem is an expression that is too complex to be generalized, make it into a function by adding an extra, unused parameter.

  • 明示的なジェネリック型パラメーターを追加します。Add explicit generic type parameters. このオプションはほとんど使用されません。This option is rarely used.

  • 次のコード例は、これらの各シナリオを示します。The following code examples illustrate each of these scenarios.

ケース 1:式が複雑すぎます。Case 1: Too complex an expression. この例では、一覧でcounterint option ref、単純な変更できない値は定義されていませんが。In this example, the list counter is intended to be int option ref, but it is not defined as a simple immutable value.

let counter = ref None
// Adding a type annotation fixes the problem:
let counter : int option ref = ref None

ケース 2:汎化できない構成要素を使用して、ジェネリック関数を定義します。Case 2: Using a nongeneralizable construct to define a generic function. この例では、コンストラクトは汎化できない構成を関数の引数の部分的なアプリケーションが伴うので。In this example, the construct is nongeneralizable because it involves partial application of function arguments.

let maxhash = max << hash
// The following is acceptable because the argument for maxhash is explicit:
let maxhash obj = (max << hash) obj

ケース 3:未使用のパラメーターを追加します。Case 3: Adding an extra, unused parameter. この式が汎化の単純でないため、コンパイラは値制限エラーを発行します。Because this expression is not simple enough for generalization, the compiler issues the value restriction error.

let emptyList10 = Array.create 10 []
// Adding an extra (unused) parameter makes it a function, which is generalizable.
let emptyList10 () = Array.create 10 []

ケース 4:型パラメーターを追加します。Case 4: Adding type parameters.

let arrayOf10Lists = Array.create 10 []
// Adding a type parameter and type annotation lets you write a generic value.
let arrayOf10Lists<'T> = Array.create 10 ([]:'T list)

最後の場合、値には型関数の場合、次のようになど多くのさまざまな種類の値を作成するために使用できるようになります。In the last case, the value becomes a type function, which may be used to create values of many different types, for example as follows:

let intLists = arrayOf10Lists<int>
let floatLists = arrayOf10Lists<float>

関連項目See also