Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# enum to string conversion

Tags:

enums

f#

I have a following F# enum

type DataType = AUCTION|TRANSACTION

I would like to use DataType as a parameter to a function, so that the values of the parameter is restricted to string AUCTION and TRANSACTION,

is that possible to convert the items in this enum to string, or is there a better way to contraint the value of a parameter to a set of string?

like image 874
tesla1060 Avatar asked Feb 28 '16 13:02

tesla1060


1 Answers

First of all, as several people have mentioned in the comments, the type you have defined is not an Enumeration, it's a Discriminated Union.

Enumerations are effectively just a label given to an integer and, in F#, are declared using this syntax:

type DataType = 
    |Auction = 1
    |Transaction = 2

Using this syntax, you've got a relationship between the value and the associated integer, you can use the integer to get the value of an Enumeration, e.g.

let transaction = enum<DataType>(2) // Transaction

Note that there is nothing stopping you from saying enum<DataType>(3537), even though we haven't defined that case.

For more details on Enumerations, see: https://msdn.microsoft.com/en-us/library/dd233216.aspx


Discriminated Unions are much more flexible than Enumerations. Let's take a look at yours:

type DataType = 
    |Auction
    |Transaction

This version is now actually a Standard .NET class with two case identifiers: Auction and Transaction. You can think of Auction and Transaction as two type constructors for DataType.

Discriminated Unions are not restricted to just simple cases, you could store additional data, e.g.

type DataType = 
    /// An auction with a list of bids
    |Auction of Bid list  
    /// A transaction with some price in GBP
    |Transaction of decimal<GBP>

With Disciminated Unions, there is no implicit relationships with integers, if we want to construct a particular case, we have to use the appropriate case identifier.

e.g. let auction = Auction (bidlist)

For more details on Discriminated Unions, see: https://msdn.microsoft.com/en-us/library/dd233226.aspx


In both cases, converting to a specific string for each case can be achieved using pattern matching.

For the Discriminated Union:

let datatypeToString datatype =
    match datatype with
    |Auction -> "AUCTION"
    |Transaction -> "TRANSACTION"

And for the Enumeration:

let datatypeToString datatype =
    match datatype with
    |DataType.Auction -> "AUCTION"
    |DataType.Transaction -> "TRANSACTION"

Notice that when you use Enumerations, F# will give you a compiler warning telling you that pattern matches cases aren't complete. This is because Enumerations are just ints and there are many ints besides just 1 and 2, this means that the match cases aren't exhaustive.

I therefore recommend you stick to Discriminated Unions and keep your exhaustive pattern matching.


P.S. If you want to go in the other direction, from string to DataType, I recommend using a tryCreateDataType function which would look something like this:

let tryCreateDataType str =
    match str with
    |"AUCTION" -> Some Auction
    |"TRANSACTION" -> Some Transaction
    |_ -> None

This returns an Option, so it will allow you to safely match against the function being successful or it failing due to an invalid string.

like image 86
TheInnerLight Avatar answered Oct 02 '22 18:10

TheInnerLight