F#模式匹配:匹配函数/子类型列表?

Li *_*oyi 5 f#

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"]))
Run Code Online (Sandbox Code Playgroud)

打印"失败"两次,因为我认为它应该,因为我给obj -> list<String>了一个功能,这不是一个obj -> list<obj>.有什么方法可以让它们匹配吗?我可以将每个列表上传到一个list<obj>之前,obj然后在它之前创建一个匿名函数,或者我可以将所有内容放到列表中.

这些都是有效的,并使它匹配,但我认为这是协方差/逆变已经解决的问题?如果我错了,请纠正我

Tom*_*cek 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
Run Code Online (Sandbox Code Playgroud)

您可以将行为封装在F#活动模式中,以使语法更好(并在类型上使用模式匹配).但是,另一个问题是,这并没有为您提供可用于动态实际调用函数的函数.我认为没有内置库函数,因此您可能需要使用.NET反射来Invoke动态调用该方法.

编辑:在SO上也有类似的相关问题.一般问题是您与特定泛型类型的某些(任何)实例化匹配,因此列表等会出现同样的问题.例如: