今日、F# を少しいじって、次のように書きました。
let sq x = x * x
let i = sq 3
let d = sq 3.0
3 行目または 4 行目のいずれかを削除するとコンパイルされますが、両方が存在する場合はコンパイルされません。
エラーが発生しますThis expression should have type 'int', but has type 'float'
。
今日、F# を少しいじって、次のように書きました。
let sq x = x * x
let i = sq 3
let d = sq 3.0
3 行目または 4 行目のいずれかを削除するとコンパイルされますが、両方が存在する場合はコンパイルされません。
エラーが発生しますThis expression should have type 'int', but has type 'float'
。
型推論は、関数sq
が typeint -> int
を持つように機能します。これは、コンパイラがその関数の使用を初めて確認したときに、整数を渡すためです。sq
したがって、これは整数を受け取る関数であると想定され、関数 ( x * x
) の定義により、整数も返されます。
F# で完全に汎用的な算術関数を定義するのは少し複雑ですが、それを行う 1 つの方法は、関数inline
を次のように作成することです。
let inline sq x = x * x
このようにして、関数の本体は呼び出しサイトで毎回インライン化されるため、インライン化sq
された関数を使用することは、使用されるたびに本体を置き換えることと同じになります。
このアプローチには欠点があり、この質問を見るのは興味深いと思います。
他の答えは正しいですが、ジグソーパズルの重要な部分を省略しています: F# では、int と float の間などの暗黙的な変換がないという事実です。これが、2 番目の呼び出しが実際に、実在しない別のオーバーロードを float 引数で呼び出している理由です。
Let バインド関数はオーバーロードできません。特定のケースではinline
、コンパイル時に関数本体をインライン化するため、適切な実装を選択できる を*
使用できます。
let inline sq x = x * x
let sq x = x * x
デフォルトの関数のタイプはint -> int
です。
これを a のコンテキストに置くとlet d = sq 3.0
、F# コンパイラはその型を として推論しfloat -> float
ます。
いずれにせよ、この関数はint->int
、 またはのいずれかの型シグネチャを 1 つだけ持つことができますfloat->float
。
これは、バインディングの実装方法の制限です。2 つの選択肢があります。
まず、宣言にインラインを追加します。
次に、クラスでメンバー バインディングを使用し、さまざまな型をオーバーライドします。