型推論の概要
F#は強い静的型付け言語ですが、値の宣言時や関数の引数宣言時にコンパイラが型を推定できない場合を除いて型を明示する必要はありません。この「コード上に型を明示しなくともコンパイラが型を推定してくれる」ことを "型推論" といいます。「型情報を明示的に指定しなくて良い」ということは、「F#が動的型付け言語である」や「F#は弱い型付け言語である」ということを意味していません。むしろF#はC#よりも強力な型推論機能を持ち合わせている言語です。
パラメータと戻り値の型推論
関数やクラスのコンストラクタのパラメータリストでは、各パラメータの型を明示的に指定する必要はありません。それでも、F#は強力な型付けをされた言語なため、コンパイル時にはすべての値と式は明確な型をもちます。また、型が特に指定されていない場合は、ジェネリック型として型推論されます。値の使用方法のすべてを満たす単一の型が存在しない場合や、値の使用方法に矛盾が存在している場合にコンパイラはエラーを報告します。
関数の戻り値の型は、「関数内の最後の式の型」によって決まります。
たとえば次のサンプルコードのパラメータ a と b は、100のリテラルが int であるため、int型だと推定されます。
let f a b = a + b + 100
つまり、上記のコードは次のようにコンパイラによって解釈されるわけです。let f (a:int) (b:int) :int = a + b + 100
また、戻り値は最後の式 [ a + b + 100 ] が int型 であることから、int型だと推定されています。自動汎化
関数の実処理がパラメータの型に依存していない場合、コンパイラはパラメータの型をジェネリック型と認識します。これは自動汎化と呼ばれ、複雑さを増すことなく一般的なコードを書くための強力な手助けになります。
たとえ、次の関数は任意の型の2つのパラメータを組み合わせてタプル型にします。
let makeTuple a b = (a, b)
このときこの関数の型は次のように推論されます。'a -> 'b -> 'a * 'b
F#プログラミングをする場合は、関数を汎用的に使えるようにするために、自動汎化が適用されるような関数を記述するように心がけましょう。