Map from discriminated union to enum

521 views Asked by At

Currently, I'm trying to teach myself some F# by making an application that consists of a C# GUI layer and an F# business layer. In the GUI layer, the user will at some point have to make a choice by selecting a value that is part of a simple enum, e.g. selecting either of the following:

enum {One, Two, Three}

I have written a function to translate the enum value to an F# discriminated union

type MyValues = 
  | One
  | Two
  | Three

Now I have to translate back, and am already tired of the boilerplate code. Is there a generic way to translate my discriminated union to the corresponding enum, and vice versa?

Cheers,

2

There are 2 answers

0
Tomas Petricek On BEST ANSWER

You can also define the enum in F# and avoid doing conversions altogether:

type MyValues = 
  | One = 0
  | Two = 1
  | Three = 2

The = <num> bit tells the F# compiler that it should compile the type as a union. When using the type from C#, this will appear as a completely normal enum. The only danger is that someone from C# can call your code with (MyValues)4, which will compile, but it will cause incomplete pattern match exception if you are using match in F#.

0
Daniel On

Here are generic DU/enum converters.

open Microsoft.FSharp.Reflection

type Union<'U>() =
    static member val Cases = 
        FSharpType.GetUnionCases(typeof<'U>)
        |> Array.sortBy (fun case -> case.Tag)
        |> Array.map (fun case -> FSharpValue.MakeUnion(case, [||]) :?> 'U)

let ofEnum e = 
    let i = LanguagePrimitives.EnumToValue e
    Union.Cases.[i - 1]

let toEnum u = 
    let i = Union.Cases |> Array.findIndex ((=) u)
    LanguagePrimitives.EnumOfValue (i + 1)

let du : MyValues = ofEnum ConsoleColor.DarkGreen
let enum : ConsoleColor = toEnum Three

It maps the DU tag to the enum underlying value.