0

型のリストによって与えられた署名を持つ関数を生成する関数「gen」を書きたいとします。

let gen (sig:Type list) = ....

let sig = [ typeof<int>; typeof<int[]>; typeof<float> ]
let func = gen sig
then func is of type: int -> int[] -> float -> unit

私は2つの可能な解決策を考えました:

a) Reflect Emit を使用していますが、この方法で IntelliSense を機能させることができるかどうかはわかりません。Reflect Emit は新しい .net コードを作成するように見えますが、IntelliSense では認識されない可能性があるため、コンパイル時にコードが検証されない可能性があります。

b) 型プロバイダーを使用していますが、重すぎて実用的ではない可能性があります。

c) のようなジェネリックを使用するgen<'T1> (sig:Type list) : 'T2 -> unitと、再帰呼び出しが必要になる場合がありますが、これを行う方法がわかりませんでした。

c) は軽量で、コンパイル時にチェックできるため、方法 c) をお勧めします。または、代替アプローチはありますか?

4

3 に答える 3

1

を参照してくださいMakeFunctionhttp://msdn.microsoft.com/en-us/library/ee353497

あなたが得ることができるものより遅いですがReflection.Emit、はるかに使いやすく、あなたの目的には十分かもしれません。

于 2012-08-02T16:34:38.253 に答える
1

特定の署名で関数を生成する方法を尋ねましたが、質問は関数の本体に関するポイントを逃しています。

この本体を設定する何らかの方法があると仮定すると、考えられる解決策の 1 つは次のようになります (警告: 内部でリフレクションを使用するため遅い):

module F = 
    type FST = Microsoft.FSharp.Reflection.FSharpType
    type FSV = Microsoft.FSharp.Reflection.FSharpValue

    let mkFunction (handler : obj list -> obj) : 'T = 
        if not (FST.IsFunction typeof<'T>) then failwith "Function type expected"
        let rec chain args ty = 
            let dty, rty = FST.GetFunctionElements ty
            let impl = 
                if FST.IsFunction rty then 
                    fun o -> chain (o::args) rty
                else
                    fun o -> handler(List.rev (o::args))
            FSV.MakeFunction(ty, impl)
        chain [] typeof<'T> :?> 'T
let f : int -> (int -> int) -> string = 
    F.mkFunction <| 
        fun [:? int as a; :? (int -> int) as f] -> 
            box (string (f a))

System.Type リストを使用して目的の署名を示したい場合 - インテリジェンスに別れを告げる

于 2012-08-02T17:55:34.943 に答える
0

プログラムを実行する前にコードを生成するために必要なすべての情報がある場合は、Reflection.Emitを使用して、前処理ステップとして関数を含むDLLを生成し、メインプロジェクトでそれを参照できます。このようにして、インテリセンスを取得します。OTOHの場合、実行時に署名しかわからない場合は、動的メソッド(http://msdn.microsoft.com/en-us/library/system.reflection.emit.dynamicmethod.aspx)を使用できますが、そうしないとわかりません。明らかに、インテリセンスを取得します。

オプションb)とc)について:前者は試していませんが、コンパイル時の操作ですが、後者はF#では不可能です。言語には可変個引数printfn&coがありません。コンパイラでベイクされます。

于 2012-08-02T07:27:05.467 に答える