If I have the following enum in F#:
type Note =
| C = 0
| D = 2
| E = 4
| F = 5
| G = 7
| A = 9
| B = 11
But at some points, I need the ordinals of the items inside of it, such that Note.C = 1, Note.D = 2,
etc. Obviously in other languages, foo.ordinal()
would work, but in here is it necessary to use a function like such:
let getNoteOrdinal = function
|Note.C -> 1
|Note.D -> 2
|Note.E -> 3
|Note.F -> 4
//etc
Is that function necessary or is there something better?
Enums in .NET are just a layer on top of an integral type, in this case your values are int
.
Per the docs, you can do a simple conversion to get that value, for example:
let value = int Note.B
Where value
in this case would be 11
.
To find the ordinal, as you can make use of a built-in function that gives you an array of all the values in order and then find the index of the one you're after. For example:
let getNoteOrdinal (note: Note) =
let values = Enum.GetValues(typeof<Note>)
Array.IndexOf(values, note) + 1
let value = getNoteOrdinal Note.E
Where value
in this case would be 3
.
You can take this one step further as @ReedCopsey suggests and make a generic function that will give you the ordinal for any enum value:
let getEnumOrdinal (e: 'a when 'a : enum<'b> and 'a : equality) =
let values = Enum.GetValues(e.GetType())
Array.IndexOf(values, e) + 1
I suggest not using an enum at all in F# unless it is required for interoperation with another .NET language. You can use a discriminated union and store the note values in an array (this is a module level value that is evaluated once when the application starts). Then you can write functions that use the array.
type Note = C | D | E | F | G | A | B
let noteValues =
[| C, 0
D, 2
E, 4
F, 5
G, 7
A, 9
B, 11 |]
let getNoteValue note =
noteValues |> Array.find (fun (n, _) -> note = n) |> snd
let getNoteOrdinal note =
noteValues |> Array.findIndex (fun (n, _) -> n = note) |> (+) 1
Example usage:
getNoteValue C // 0
getNoteValue D // 2
getNoteOrdinal C // 1
getNoteOrdinal D // 2
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