48

複数のタイプのパラメーター (int と int64 など) で機能する関数を定義する方法を見つけようとしています。私が理解しているように、関数のオーバーロードは F# では不可能です (確かにコンパイラは文句を言います)。たとえば、次の関数を考えてみましょう。

let sqrt_int = function
    | n:int   -> int (sqrt (float n))
    | n:int64 -> int64 (sqrt (float n))

もちろん、コンパイラは構文が無効であると不平を言います(パターンマッチングの型制約はサポートされていないようです)が、これは私が達成したいことを示していると思います.タイプ。これは、ジェネリック型/型推論/パターン マッチングの組み合わせを使用する F# で可能であると感じていますが、構文がわかりませんでした。:? も使用してみました。演算子 (動的型テスト) とwhen句をパターン マッチング ブロックに追加しますが、これでもすべての並べ替えエラーが発生します。

私は言語に慣れていないので、ここで不可能なことをしようとしている可能性が非常に高いので、別の解決策があれば教えてください。

4

5 に答える 5

64

通常、オーバーロードは型推論言語の厄介な問題です (少なくとも、F# のように、型システムが型クラスを含むほど強力でない場合)。F# にはいくつかの選択肢があります。

  • メソッド (型のメンバー) でオーバーロードを使用します。この場合、オーバーロードは他の .Net 言語と同じように機能します (パラメーターの数/型によって呼び出しを区別できる場合は、メンバーをアドホックにオーバーロードできます)。
  • 関数のアドホック オーバーロードには、「インライン」、「^」、および静的メンバー制約を使用します (これは、int/float/etc で動作する必要があるさまざまな数学演算子のほとんどです。ここでの構文は奇妙です。 F# ライブラリ以外はほとんど使用されていません)
  • 追加の操作辞書パラメーターを渡すことによって型クラスをシミュレートします (これは、任意のユーザー定義型のさまざまな数学アルゴリズムを一般化するために、F# PowerPack ライブラリの 1 つで INumeric が行うことです)。
  • 動的型付けにフォールバックします (「obj」パラメーターを渡し、動的型テストを実行し、不正な型に対して実行時例外をスローします)。

あなたの特定の例では、おそらくメソッドのオーバーロードを使用するだけです:

type MathOps =
    static member sqrt_int(x:int) = x |> float |> sqrt |> int
    static member sqrt_int(x:int64) = x |> float |> sqrt |> int64

let x = MathOps.sqrt_int 9
let y = MathOps.sqrt_int 100L
于 2009-02-01T18:50:49.253 に答える
20

これは機能します:

type T = T with
    static member ($) (T, n:int  ) = int   (sqrt (float n))
    static member ($) (T, n:int64) = int64 (sqrt (float n))

let inline sqrt_int (x:'t) :'t = T $ x

静的な制約とオーバーロードを使用して、コンパイル時に引数の型を検索します。

静的制約は、オペレーター ($この場合はオペレーター) の存在下で自動的に生成されますが、常に手動で記述することができます。

type T = T with
    static member Sqr (T, n:int  ) = int   (sqrt (float n))
    static member Sqr (T, n:int64) = int64 (sqrt (float n))

let inline sqrt_int (x:'N) :'N = ((^T or ^N) : (static member Sqr: ^T * ^N -> _) T, x)

詳細については、こちらをご覧ください。

于 2013-09-28T20:40:19.313 に答える
15

はい、これは可能です。このhubFSスレッドを見てください。

この場合、解決策は次のようになります。

let inline retype (x:'a) : 'b = (# "" x : 'b #)
let inline sqrt_int (n:'a) = retype (sqrt (float n)) : 'a

警告: コンパイル時の型チェックはありません。sqrt_int "blabla"つまり、正常にコンパイルされますが、実行時に FormatException が発生します。

于 2009-02-01T16:42:26.627 に答える
10

ランタイム型チェックを使用する別の方法を次に示します...

let sqrt_int<'a> (x:'a) : 'a = // '
    match box x with
    | :? int as i -> downcast (i |> float |> sqrt |> int |> box)
    | :? int64 as i -> downcast (i |> float |> sqrt |> int64 |> box)
    | _ -> failwith "boo"

let a = sqrt_int 9
let b = sqrt_int 100L
let c = sqrt_int "foo" // boom
于 2009-02-01T21:21:16.187 に答える
3

すでに提供されている正解から離れることはありませんが、実際にはパターン マッチングで型制約を使用できます。構文は次のとおりです。

| :? type ->

または、型チェックとキャストを組み合わせたい場合:

| :? type as foo ->
于 2009-02-01T19:10:01.960 に答える