F# Pattern Matching: Matching functions/lists of subtypes?

守給你的承諾、 提交于 2019-12-06 02:43:07

问题


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"]))

prints "fail" twice, as I suppose it should, because I am giving i a function obj -> list<String>, which is not a obj -> list<obj>. Is there any way to make them match though? I could upcast each list into a list<obj> before making an anonymous function out of it, or I could upcast everything to obj before putting it into the list.

Either of those works and makes it match, but i thought this was the problem that covariance/contravariance was meant to have already solved? Correct me if i'm mistaken


回答1:


Unfortunately, you can't solve this using any built-in pattern matching.

The only way to find out whether an obj value is some F# function is to use F# Reflection and call the FSharpType.IsFunction method on the type. You can check for the case in your example like this:

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

You could encapsulate the behavior in an F# active pattern to make the syntax a bit nicer (and use pattern matching on types). However, another problem is that this doesn't give you a function that you could use to actually invoke the function dynamically. I don't think there is a built-in library function for this, so you'll probably need to use .NET reflection to call the Invoke method dynamically.

EDIT: There has been similar related questions on SO. The general problem is that you're matching against some (any) instantiation of a specific generic type, so the same issue arises with lists etc. See for example:

  • F# and pattern matching on generics...
  • Pattern matching against generic type...
  • How to cast an object to a list...


来源:https://stackoverflow.com/questions/8169233/f-pattern-matching-matching-functions-lists-of-subtypes

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!