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>
,然后再创建一个匿名函数,或者我可以将所有内容转发到obj
,然后再将其放入列表中。
其中任何一个都可以使它匹配,但我认为这是协方差/逆变已经解决的问题?如果我弄错了,请纠正我
答案 0 :(得分: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上也有类似的相关问题。一般的问题是你匹配特定泛型类型的某些(任何)实例化,因此列表等也会出现同样的问题。例如:参见: