vendredi 21 juillet 2017

Unboxing values of F# discriminated unions

Some functions of my F# code receive values boxed as object even though the underlying values are typed. If the value is a discriminated union, it's not possible to unbox it back to its F# type. Here is 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 output from this example is "match via reflection", ResultA is never matched because the boxed value is of a different CLR type - Result.Ok. Since F# discriminated union cases are represented as its own types, the boxed value doesn't match the type ResultA. Moreover, it's not possible to match it to ResultA.OK because inside F# code it's not a legal type. The only option seems to be manual instantiation of a value using reflection, which is inefficient and silly because the value is already instantiated, it's here, it just can not be accessed in F# code once it's boxed.

Am I overlooking something? Is there a more straightforward way of unboxing an F# discriminated union value?





Aucun commentaire:

Enregistrer un commentaire