Marko Grdinić
Marko Grdinić

Reputation: 4062

How to do the equivalent of pattern matching on native .NET types?

let print_type_c (x: Type)= 
    if x = typeof<Int32> then "int"
    elif x = typeof<Single> then "float"
    elif x = typeof<Tuple<_>> then "tuple"
    elif x = typeof<FSharpFunc<Tuple<'inp>,'out>> then "function..."
    else failwithf "Not supported(%A)" x

print_type_c (typeof<int>) // prints int
print_type_c (typeof<float32>) // prints float
print_type_c (typeof<int*int>) // throw an exception

I am trying to build a primitive F# quotations to Cuda compiler and I need to figure out how to translate tuple types to C struct types in function declarations, but I am really not familiar with how the .NET machinery works. It is disappointing that F# quotations do not return you a nice AST based on discriminated unions which would make everything explicit, but unless I want to do the typechecking myself, I'll have work with this.

What I am asking is - is there a way to the crappy piece of code above with pattern matching on .NET Types, because the above is clearly not working.

Edit: The question is not a duplicate because that linked question is asking how to print the properties of F# records, while I am asking how to print the types of native .NET types (including functions) inside F# quotations. A visual scan of the accepted answer here and there should show that they are completely different and not even using the same functions.

Upvotes: 2

Views: 105

Answers (1)

Fyodor Soikin
Fyodor Soikin

Reputation: 80744

Runtime type inference? On types not known at compile time? No, sorry, doesn't exist, you'll have to build one yourself.

To check if a particular type is an instance of a specific generic type, you need to see if it's generic in the first place, and then get its generic definition, and compare that:

if x.IsGenericType && (x.GetGenericTypeDefinition() = typeof<System.Tuple<_>>.GetGenericTypeDefinition()) then "tuple" else "not"

Note that there is not just one Tuple type, but many - Tuple<_>, Tuple<_,_>, Tuple<_,_,_>, and so on - up to 8.

Same goes for FSharpFunc:

if x.IsGenericType && (x.GetGenericTypeDefinition() = typeof<FSharpFunc<_,_>>.GetGenericTypeDefinition()) then "function" else "not"

To get generic arguments of a type, use .GetGenericArguments():

if x.IsGenericType && (x.GetGenericTypeDefinition() = typeof<FSharpFunc<_,_>>.GetGenericTypeDefinition()) 
then 
    sprintf "function %s -> %s" (x.GetGenericArguments().[0].Name) (x.GetGenericArguments().[1].Name)
else 
    "not function"

Upvotes: 2

Related Questions