Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enumerate a discriminated union in F#?

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.

like image 612
michelpm Avatar asked Aug 09 '11 13:08

michelpm


People also ask

How is a discriminated union defined?

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.

Are the unions of F# discriminated briefly explain?

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.

What is a tagged union C++?

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).


2 Answers

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 
like image 135
Robert Avatar answered Oct 01 '22 12:10

Robert


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.

like image 43
Tomas Petricek Avatar answered Oct 01 '22 13:10

Tomas Petricek