I have an enumeration in F#, like this:
type Creature =
| SmallCreature = 0
| MediumCreature = 1
| GiantCreature = 2
| HumongousCreature = 3
| CreatureOfNondescriptSize = 4
I do not like manually typing out numbers, and I want to easily insert more items in the enumeration later without having to shift the numbers.
I tried this
type Creature =
| SmallCreature
| MediumCreature
| GiantCreature
| HumongousCreature
| CreatureOfNondescriptSize
but it caused an error The type 'Creature' is not a CLI enum type
later in the program
let input = Int32.Parse(Console.ReadLine())
let output = match EnumOfValue<int, Creature>(input) with // <---Error occurs here
| Creature.SmallCreature -> "Rat"
| Creature.MediumCreature -> "Dog"
| Creature.GiantCreature -> "Elephant"
| Creature.HumongousCreature -> "Whale"
| Creature.CreatureOfNondescriptSize -> "Jon Skeet"
| _ -> "Unacceptably Hideous Monstrosity"
Console.WriteLine(output)
Console.WriteLine()
Console.WriteLine("Press any key to exit...")
Console.Read() |> ignore
How can I define an enumeration without manually assigning number values to each item?
The keyword 'enum' is used to declare new enumeration types in C and C++. Following is an example of enum declaration. // The name of enumeration is "flag" and the constant // are the values of the flag.
In computer programming, an enumerated type (also called enumeration, enum, or factor in the R programming language, and a categorical variable in statistics) is a data type consisting of a set of named values called elements, members, enumeral, or enumerators of the type.
Enumeration means counting or reciting numbers or a numbered list. A waiter's lengthy enumeration of all the available salad dressings might seem a little hostile if he begins with a deep sigh. When you're reciting a list of things, it's enumeration.
An enumerated type is a type whose legal values consist of a fixed set of constants. Common examples include compass directions, which take the values North, South, East and West and days of the week, which take the values Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, and Saturday.
Unfortunately, you can't. Are the numeric values important? If so, it somewhat escapes the intended use of enums (flags aside). You might consider a class or discriminated union in that case.
Your second example is, in fact, a discriminated union. But your later use of EnumOfValue
, which expects an enum, is causing the error.
Another option is to store the enum to number mapping in a dictionary and replace the pattern matching with a dictionary lookup. Then, the numeric value of the enum would be irrelevant.
I agree that manually managing enum values is burdensome. I hope it's addressed in a future version.
As Daniel says, you can't define an enum without specifying the numeric equivalents. However, you can define a function which converts a number to the corresponding case of a discriminated union:
open Microsoft.FSharp.Reflection
let intToDU<'t> n =
if not (FSharpType.IsUnion typeof<'t>) then
failwithf "%s is not a discriminated union" typeof<'t>.Name
let cases = FSharpType.GetUnionCases(typeof<'t>)
if n >= cases.Length || n < 0 then
failwithf "%i is out of the range of %s's cases (0 - %i)" n typeof<'t>.Name (cases.Length - 1)
let uc = cases.[n]
if uc.GetFields().Length > 0 then
failwithf "%s.%s requires constructor arguments" typeof<'t>.Name uc.Name
FSharpValue.MakeUnion(uc, [||]) :?> 't
Then you can use this generic function like this:
type Creature =
| SmallCreature
| MediumCreature
| GiantCreature
| HumongousCreature
| CreatureOfNondescriptSize
let input = int (System.Console.ReadLine())
let output =
match intToDU input with
| SmallCreature -> "Rat"
| Creature.MediumCreature -> "Dog"
| Creature.GiantCreature -> "Elephant"
| Creature.HumongousCreature -> "Whale"
| Creature.CreatureOfNondescriptSize -> "Jon Skeet"
This has the added benefit that the pattern match is now total.
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