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
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With