5

次の(簡略化された)スニペットは、静的に解決された型パラメーターを一貫して使用する、私が実装しているアプリケーションから抜粋したものです。

type A< ^B when ^B : (static member MyMember : Unit -> Unit)> = {
  Field : unit
}
type TestA = {
  AField : A< BTy >
}
and BTy = {
  BField : Unit
} with
  static member MyMember () = ()

IntelliSenseは、フィールドAField(AField : A< BTy >)のタイプを定義すると、次のエラーを表示します。タイプ'BTy'は、'MyMember'という名前の演算子をサポートしていません

編集済み。それらを別々に宣言することは機能しますが、相互参照があり、2つのタイプの共通の情報を含む上部に配置する3番目のタイプを宣言できない場合。この問題を回避するにはどうすればよいですか?とにかく、それが機能する定義の下で定義するlet pluto = ("" :> obj) :?> A< BTy >と、両方のタイプがletバインディングから見えるので想像します。

4

2 に答える 2

12

正直なところ、型宣言で静的メンバー制約を使用することさえ許可されていることに少し驚いていますが、@pad で述べたように、宣言を正しい順序で配置して再帰を削除すると、機能します (ただし、より複雑な例に移行するときに他の制限がないかどうかはわかりません):

type A< ^B when ^B : (static member MyMember : Unit -> Unit)> = 
  { Field : unit } 

type BTy = 
  { BField : Unit } 
  static member MyMember () = () 

type TestA = { AField : A<BTy> }

とにかく、型宣言で静的メンバー制約を使用するのは少し複雑だと思います。これを行うためのよりクリーンな方法は、必要なメンバーを明確に記述 (および文書化) するインターフェースを定義することです。

type IMyMember =
  abstract MyMember : unit -> unit

現在は、静的メンバー制約を使用して、必要なメンバーを持つがインターフェイスを実装していない型からインターフェイスの実装を作成できます。この手法を使用すると、型の静的メンバー制約とまったく同じ機能を実装できるはずです (ただし、より明確な方法で)。

/// Captures 'IMyMember' implementation from another type using static constraints
let inline captureMyMember< ^B when ^B : (static member MyMember : Unit -> Unit)> =
  { new IMyMember with
      member x.MyMember () = 
        (^B : (static member MyMember : Unit -> Unit) ()) }

関数は、たとえば、型から作成IMyMemberします。BTy

/// A type that contains field and a captured implementation of 'IMyMember'
type A = 
  { Field : unit 
    Operations : IMyMember } 

let it = { Field = ()
           Operations = captureMyMember<BTy> }

余談ですが、一般的な数値コードの書き方を示す記事で同じ手法を使用しましたが、そこでは非常にうまく機能したと思います。

于 2012-10-15T00:07:17.023 に答える
0

あなたの実装 @Tomas は質問を満たしていますが、関数型プログラミングのパラダイムを尊重していないため、ソリューションのスタイルにはためらいがあります。Haskell の Type Classes 実装から生じる解決策を考えました。インターフェイス、抽象クラスなどは、F# 環境が .Net 環境と「対話」できるようにするために実装されています。これは、スタイルの統一性のために、インターフェイス、抽象クラスなどを実装するコードを使用するコンテキストで使用されます。 .Net ライブラリと対話する必要はありません。私の意見では、これは「オーバーヘッド」です (ただし、F# はマルチパラダイム言語です)。これが、Haskell の型クラスの実装が非常に洗練されている理由です。以下では、F# を使用して「Haskell Type Class」コードを実装し、問題を解決しました。

type Operations< ^a> = 
  {  
    MyMember : unit -> unit
  }

type A< ^a> = {
  Operations : Operations< ^a>
}

and TestA = { 
  AField : A< BTy > 
}

and BTy = { 
  BField : Unit 
}

let it = 
  let BTy_operations : Operations< BTy > = { MyMember = fun () -> () }
  let A_of_BTy = { Operations = BTy_operations }
  { AField = A_of_BTy }
于 2012-10-15T21:53:20.830 に答える