3

let inline と member 制約を使用すると、既知のメンバーに対してダック タイピングを行うことができますが、次のようなジェネリック関数を定義したい場合はどうでしょうか。

let ダックラッパー<'a> アヒル = ...

署名 'b -> 'a を使用し、戻り値は 'a (インターフェース) を実装し、duck への呼び出しを転送するオブジェクトになります。

Reflection.Emit を使用して C# でこれを実行しましたが、F# のリフレクション、引用符、またはその他の構成要素を使用すると簡単になるかどうか疑問に思っています。

これを達成する方法について何か提案はありますか?

Timsの回答を読んだ後に編集 して、もう少し詳細を説明したいと思いました

引用を使って助けることについて書いたとき、私が考えていたのは次のようなものでした:

{new IInterface with member x.SayHello() = !!<@ %expr @>}

!! 引用符を関数に変換する演算子であり、 %expr はメソッドの作業単位です。式を関数に変換することはできますが(推測します)、方法がわかりません

IInterface は 'a になるので、もちろん、これでうまくいくわけではありません。F# リフレクションが便利な関数を持ち、型オブジェクトといくつかの関数値に基づいて型を構築できることを願っています。

EDIT Tomas Petricekの回答の更新として、私のニーズを説明するコードをいくつか提供します

type SourceRole =
   abstract transfer : decimal -> context

and context(sourceAccount:account, destinationAccount) =
   let source = sourceAccount
   let destination = destinationAccount

   member self.transfer amount = 
     let sourcePlayer = 
       {new SourceRole with
          member this.transfer amount =
              use scope =  new TransactionScope()
              let source = source.decreaseBalance amount
              let destination = destination.increaseBalance amount
              scope.Complete()
              context(source,destination)
              }
     sourcePlayer.transfer(amount)

これは、 DCIの教科書の例をF# に移植する試みです。ソースと宛先は DCI ロールです。特定のコントラクトに準拠するデータ オブジェクトは、それらを再生できるという考えです。この場合、契約は簡単です。source には reduceBalance というメンバー関数が必要であり、destination には increaseBalance というメンバー関数が必要です。この特定のケースでは、let inline とメンバーの制約を使用してそれを実現できます。しかし、インターフェイスとオブジェクトを指定した一連の関数を書きたいと思います。この場合、それはソース (オブジェクトとして) であり、

type sourceContract = 
   abstract decreaseBalance : decimal -> sourceContract

タイプとして。結果は、ソース オブジェクトの同じ名前のメソッドにメソッド呼び出しをパイプする sourceContract 型のオブジェクトになります。

4

2 に答える 2

4

F# リフレクション ( Microsoft.FSharp.Reflection) は、プレーンな API の F# に適したラッパーであるSystem.Reflectionため、ここでは何も追加しないと思います。

引用符は新しい型を定義できません: (インターフェースベースのダックタイピングを行うには、新しい型を定義する必要があります)

> <@ { new IInterface with member x.SayHello = "hello" } @>;;

  <@ { new IInterface with member x.SayHello = "hello" } @>;;
  ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(7,4): error FS0449: Quotations cannot contain object expressions
> <@ type Test() = class end @>;;

  <@ type Test() = class end @>;;
  ---^^^^

stdin(8,4): error FS0010: Unexpected keyword 'type' in quotation literal

Reflection.Emit は、これを使用する方法です。

編集:

型オブジェクトといくつかの関数値に基づいて型を構築できるように、F# リフレクションに便利な関数がいくつかあることを願っています。

そうではないのではないかと思います。F# リフレクションに関するドキュメントは次のとおりです: http://msdn.microsoft.com/en-gb/library/ee353491.aspx

于 2010-12-14T14:33:18.677 に答える
2

F# PowerPackのコンポーネントを使用して F# の引用をコンパイルできます。したがって、引用符を使用して、実行時にコードを生成および実行できると思います。関数を表す引用符を書いてコンパイルすると、インターフェイスを実装するために使用できる関数値が得られます。以下は簡単な例です。

#r "FSharp.PowerPack.Linq.dll"
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation

// Create a part using "Expr." calls explicitly
let expr = Expr.Value(13)
// Create a part using quotation syntax 
let expr2 = <@ (fun x -> x * %%expr) @>

// Compile & Run
let f = expr2.Compile()()
f 10

引用構文と への呼び出しを混在Exprさせることができるため、基本的なブロックからコードを簡単に作成できます。コンパイルは (現在のところ) 少しばかげているため、生成されたコードは通常の F# コードほど効率的ではありません (ただし、自分のケースでそれを測定する必要があります)。

あなたが何をしようとしているのか正確に理解しているかどうかはよくわかりませんので、詳細を提供していただければ、より具体的な回答を差し上げることができます。

于 2010-12-14T23:43:12.553 に答える