4

私はF#で、型引数が加算をサポートする必要があるジェネリックインターフェイスを作成しようとしているので、次のようになりました。

type IMyInterface<'b when 'b : (static member (+) : 'b * 'b -> 'b)> =
    abstract member myFunction : 'b -> 'b

残念ながら、このコードでは次のエラーが発生します。

このコードは十分に一般的ではありません。^ D:比較および^ D:(静的メンバー(+):^ D * ^ D-> ^ D)の場合、型変数^ Dは、スコープをエスケープするため、一般化できませんでした。

同じ問題に関してこの質問を見つけましたが、関数をとしてマークする必要がある理由がわかりませんinline

また、抽象メンバーを作成できないのでinline、特定の例で使用できる別のソリューションはありますか?それとも、これを達成するためのまったく別の方法を見つける必要がありますか?

4

2 に答える 2

8

まず第一に、インターフェイスの型パラメータが加算をサポートしていると述べる必要がある理由を完全には理解していないと思います-加算はの実装で使用されると思いますMyFunction。その場合、インターフェイスの呼び出し元は知る必要はありませんそれについて。追加を公開したい場合は、別のメソッドとして追加するだけです。

type IMyInterface<'T> =
  abstract Add : 'T * 'T -> 'T
  abstract MyFunction : 'T -> 'T

inline静的メンバーの制約は、関数や静的メンバー以外の場所ではうまく機能しないと思いますinline(ただし、間違っている可能性があります)。ジェネリック型内で数値演算を使用する必要がある場合は、実装を(メソッド内で)キャプチャinlineしてインターフェイスに格納するトリックを使用できます。F#の一般的な数学についての私のブログの最後にこの例があります。

秘訣は、必要な数値演算を使用してインターフェースを定義し、それを追加の引数としてコンストラクターに渡すことです。

type IAddition<'T> =
  abstract Add : 'T * 'T -> 'T

type MyType<'T>(a:'T, b:'T, add:IAddition<'T>) =
  member x.Sum = add.Add(a, b)

これまでのところ、これは標準の.NETの方法でインターフェイスを使用しています。インターフェイスは数値演算を表し、インターフェイスを介してそれらを呼び出します。ここでの秘訣は、2つの引数だけを取り、静的制約として必要とするinlineメソッドを追加することです。次に、メソッドはインターフェースを実装し、それを最後のパラメーターとしてに渡すことができます。Create+MyType

  static member inline Create(a:^N, b:^N) =
    let ops = 
      { new IAddition< ^N > with
          member x.Add(a, b) = a + b }
    MyType< ^N >(a, b, ops)

これで、書き込みが可能にMyType<_>.Create(1, 2)なり、整数の+操作が自動的にキャプチャされてインターフェイスに格納されます(コードの残りの部分での作業が簡単になります)。

于 2013-03-26T13:56:40.820 に答える
2

MSDNの静的に解決されたタイプパラメータにより、の必要性が明確になる場合がありinlineます。肝心なのは、インターフェースに制約を課すことはできず、それが必要な場所でもないということです。(実装の詳細に相当するインターフェースを本当に「リーク」したいですか?この制約はコンパイル時にのみ存在することを忘れないでください。)関数はである可能性があるinlineため、これは機能します。

type IMyInterface<'b> =
    abstract member myFunction : 'b -> 'b

// (^b : (static member (+) ...) constraint is inferred
let inline makeMyInterface() =
  { new IMyInterface<_> with
      member x.myFunction b = b + b }
于 2013-03-26T13:56:27.447 に答える