How can I enumerate through the possible "values" of a discriminated union in F#?
I want to know if is there something like Enum.GetValues(Type)
for discriminated unions, tough I am not sure over what kind of data I would enumerate. I would like to generate a list or array of a discriminated union with one item for each option.
Discriminated unions are useful for heterogeneous data; data that can have special cases, including valid and error cases; data that varies in type from one instance to another; and as an alternative for small object hierarchies. In addition, recursive discriminated unions are used to represent tree data structures.
In F#, a sum type is called a “discriminated union” type. Each component type (called a union case) must be tagged with a label (called a case identifier or tag) so that they can be told apart (“discriminated”). The labels can be any identifier you like, but must start with an uppercase letter.
Simply put, tagged unions are unions that have associated with them a piece of data that tracks which of the potential union properties is currently set. In C++ you can choose between structs and classes to encapsulate the union, or develop your own custom data structure base solution (like a map).
Yes, F# has it's own reflection layer build on top of .NET's reflection to help you make sense of types that are specific to F#, like discriminating unions. Here's the code that will let you enumerate a union's cases:
open Microsoft.FSharp.Reflection type MyDU = | One | Two | Three let cases = FSharpType.GetUnionCases typeof<MyDU> for case in cases do printfn "%s" case.Name
To slightly extend Robert's example - even if you don't have an instance of the discriminated union, you can use F# reflection to get the information about the type (such as types of the arguments of individual cases). The following extends Robert's sample ans it also prints the types of arguments:
open Microsoft.FSharp.Reflection let ty = typeof<option<int>> let cases = FSharpType.GetUnionCases ty printfn "type %s =" ty.FullName for case in cases do printf "| %s" case.Name let fields = case.GetFields() if fields.Length > 0 then printf " of" for fld in fields do printf " %s " fld.PropertyType.FullName printfn ""
For example, for option<int>
type, you'll get (I slightly simplified the output):
type Microsoft.FSharp.Core.FSharpOption`1[System.Int32] = | None | Some of System.Int32
There are many interesting uses for this information - for example, you could generate DB schema from F# unions or to create functions that will parse XML into a discriminated union (that describes the structure). I talked about the XML processing sample at GOTO conference earlier this year.
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