Frage

I wrote this code

type Test =
    | Age of int
    | Name of string;;

let x = Age(10);;


if (x.GetType() = typeof<Test>) then printfn "true" else printfn "false";;

The code prints false. But that puzzles me because isn't Age of type Test?

Also, is there a better way to compare types in F# the .GetType() = typeof<> is very long. I tried :? but I think that's for typecasting rather than comparing types.

War es hilfreich?

Lösung

The plain answer is, do so:

if (x :> obj) :? Test then printfn "true" else printfn "false"

This issue comes because of the implementation of DUs (using internal classes and tags) and the limitation of F#'s type system (which does not acknowledge the implementation).

As you saw, the type of x is FSI_0001+Test+Age, and F# does not recognize that as a sub-type of Test.

Andere Tipps

Quoting from the spec

A compiled union type U has:

· One CLI static getter property U.C for each null union case C. This property gets a singleton object that represents each such case.

· One CLI nested type U.C for each non-null union case C. This type has instance properties Item1, Item2.... for each field of the union case, or a single instance property Item if there is only one field. However, a compiled union type that has only one case does not have a nested type. Instead, the union type itself plays the role of the case type.

We see that Age is implemented as a nested type of the parent DU. As a result you could use Type.GetNestedTypes to get all the subtypes of the DU and then test each one to see if the type matches.

But that puzzles me because isn't Test of type Color?

There is no type Color and Test is a type itself so it does not have a type. So your question is nonsensical.

Perhaps you meant to ask why the answer is what it is? If so, it is a consequence of the way F# currently chooses to represent such values internally.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top