Unboxing F # values ​​of discriminated joins

Some of the functions in my F # code take values ​​marked as objects, even though basic values ​​are typed. If the value is a discriminatory union, there is no way to cast it back into its F # type. Here's a simple example:

type Result<'TOk,'TError> = 
| Ok of 'TOk 
| Error of 'TError

type ResultA = Result<string, int>

let a = Ok "A"
let o = box a

match o with
| :? ResultA -> printfn "match ResultA"
// | :? ResultA.Ok -> printfn "match" // doesn't compile
| _ when o.GetType().DeclaringType = typedefof<ResultA> -> printfn "match via reflection"
| _ -> printfn "no match"

      

The result from this example is "match through reflection", ResultA is never matched because the nested value has a different CLR type, Result.Ok. Because F # random joins are represented as native types, the value in the box does not match the ResultA type. Moreover, it is not possible to map it to ResultA.OK, because within the F # code, it is not a legal type. The only option is to manually create the value using reflection, which is inefficient and stupid because the value has already been created, it is here, it simply cannot be accessed in the F # code after inserting it.

Am I missing something? Is there an easier F # way to unboxing a discriminated union value?

+3


source to share


1 answer


You are just conforming to a different type. Your variable is a

not a type ResultA

, but a generic type Result<string, 'a>

that binds to when inserted Result<string, obj>

.

Alternatively, make the variable have the correct type explicitly:

let a : ResultA = Ok "A"

      

Or a match with the correct type:

match o with
| :? Result<string, obj> -> printfn "match ResultA"

      

Both options will work.




A note on your guess :

ResultA is never matched because the nested value has a different CLR type - Result.Ok

This is not the reason. Type matching works the same way as the is

/ operators as

in C #, that is, it matches subtypes as well as the exact type. DU members are compiled as subtypes of the DU type itself. This is how F # can force .NET to treat different cases as one type.

A note on runtime typing in general : You
do not need to handle types at runtime. Try to avoid this if at all possible. There must be a rule of thumb, if you find yourself working with types at runtime, you've probably modeled something wrong.

This is especially true if you don't know exactly how things work.

+4


source







All Articles