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

我想到了两种可能的解决方案:

a) 使用 Reflect Emit,但我不知道这样我们是否可以让 IntelliSense 工作?Reflect Emit 似乎创建了 IntelliSense 可能看不到的新 .net 代码,因此它可能不会在编译时验证代码。

b)使用类型提供者,但我担心它太重并且可能不实用。

c)使用泛型,如gen<'T1> (sig:Type list) : 'T2 -> unit,这可能需要递归调用,但我不知道如何做到这一点。

我更喜欢方法 c),因为它是轻量级的,并且可以在编译时检查。还是有替代方法?

4

3 回答 3

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 回答
1

MakeFunction请参阅http://msdn.microsoft.com/en-us/library/ee353497

比你能得到的要慢Reflection.Emit,但更容易使用,可能足以满足你的目的。

于 2012-08-02T16:34:38.253 回答
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 回答