2011-11-17 80 views
5
let f (O: obj) = 
    match O with 
     | :? (obj -> list<obj>) -> "win" 
     | :? list<obj> -> "list!" 
     | _ -> "fail" 

Console.WriteLine(f(fun x -> ["lol"])) 
Console.WriteLine(f(["lol"])) 

打印“失败”两次,我想它应该,因为我给我一个功能obj -> list<String>,这不是obj -> list<obj>。有什么方法可以让它们匹配吗?在匿名函数出来之前,我可以将每个列表上传到list<obj>,或者在把它放入列表之前,我可以将所有内容上传到objF#模式匹配:匹配函数/子类型列表?

这些作品中的任何一个都可以匹配,但我认为这是协变/逆变意味着已经解决的问题?纠正我,如果我错了

+2

F#不支持co/contravariance。 – Daniel

回答

7

不幸的是,你不能解决这个使用任何内置的模式匹配。

要找出obj值是否为F#函数的唯一方法是使用F#Reflection并调用该类型的FSharpType.IsFunction方法。您可以检查像这样在你的榜样的情况:

open System  
open Microsoft.FSharp.Reflection  

let f (o : obj) = 
    let ty = o.GetType() 
    if FSharpType.IsFunction(ty) then 
    let tyFrom, tyTo = FSharpType.GetFunctionElements(ty) 
    if tyTo.IsGenericType && tyTo.GetGenericTypeDefinition() = typedefof<list<_>> then 
     printfn "win" 
    else 
     printfn "wrong function" 
    else 
    printfn "not a function" 

Console.WriteLine(f(fun x -> "lol")) // wrong function 
Console.WriteLine(f(fun x -> ["lol"])) // win 
Console.WriteLine(f(["lol"]))   // not a function 

你可以封装的行为在F#活跃模式,使语法更好一点(和使用模式的类型匹配)。但是,另一个问题是,这不会给你一个你可以用来动态调用函数的函数。我不认为这是一个内置的库函数,因此您可能需要使用.NET反射来动态调用Invoke方法。

编辑:在SO上也有类似的相关问题。普遍的问题是,你对一个特定的泛型类型的一些(任何)实例化匹配,所以同样的问题与列表等见例如出现了: