9

私はまだ、F# がどのように関数と型を一般化するか (または一般化しないか) について頭を悩ませようとしています。

let min(a, b) = if a < b then a else b

let add(a, b) = a + b

let minInt = min(3, 4)
let minFloat = min(3.0, 4.0) // works!

let addInt = add(3, 5)
let addFloat = add(3.0, 5.0) // error: This expression was expected to have type
                             // int but here has type float

ここで、 min はジェネリック型'a * 'a -> 'a (requires comparison)を持ち、 add は具象型を持ちint * int -> int、プログラムでの最初の使用から明らかに推測されます。どちらも同じように宣言され、使用されますが、一般化の違いはなぜでしょうか?

add の場合、関数をインラインで宣言することで問題を回避できることを理解しています。これにより、ジェネリック型定義が取得されます'a * 'b -> 'c (requires member (+))。他の。

4

3 に答える 3

7

ここに@TomasPによるこの問題に関する優れた記事があります:http://toasp.net/blog/fsharp-generic-numeric.aspx

いくつかの型パラメーター 'T を持つ単純な汎用コードを作成する場合、型パラメーターについて何も知らず、コードで使用する必要がある可能性のあるすべての演算子を提供する数値型に制限する方法がありません。これは .NET ランタイムの制限であり、F# はそれを克服するための 2 つの方法を提供します。

しかし、なぜ<>(および拡張により 、=<=および>=) が OK なのですか?

F# コンパイラはequalityand を異なる方法で扱います (仕様comparisonのセクション 5.2.10 等価性と比較制約を参照してください。@Daniel に感謝します)。次の場合に許可される特別な制約を取得します(単純に、詳細については仕様を参照してください)。 comparison

型が名前付き型である場合、型定義は NoComparison 属性を持たず、また持つと推測されず、型定義は System.IComparable を実装するか、配列型であるか、System.IntPtr であるか、または System.UIntPtr です。 .

+オペレーターにとって、そのような特別な処理はありません。のような制約が存在しないのはなぜnumericですか?

その演算子は文字列に対しても定義されていませんか? リストとコレクションの一部の言語では? 確かにそれはaddable制約であり、そうではありませんnumeric。次に、そのようなオーバーロードされた演算子が、異なる意味を持つプログラムで多数見つかります。そのため、F# は、静的メンバー制約と inline キーワードを使用した「キャッチオール」メソッドを提供します。equalityとだけcomparisonが特別です。

于 2012-05-14T20:30:30.053 に答える
2

一般化の違いはなぜですか?

一般性とパフォーマンスの間にはトレードオフがあります。comparison制約は、任意の F# 型の任意の値に作用するような関数に一般性を提供しますがmin、一般的なケースでは、仮想ディスパッチに頼るため、何倍も遅くなります。演算子は制限された+一般性を提供し、オーバーロードで拡張された任意の F# 型の任意の値を操作できますが、一般的なケースでは機能しません。したがって、ディスパッチが必要ないため、常に非常に高速です。

于 2012-05-19T00:23:36.743 に答える
1

comparisonコンパイル時の制約です。疑問が残ります: なぜadd一般化されていないのでしょうか? yamen が指摘したように、一般的な数学演算にはインライン展開が必要であり、これはコード サイズとパフォーマンスに影響します。おそらく、コンパイラが自動的に行うべきものではありません。

于 2012-05-14T19:30:44.190 に答える