Search code examples
f#literalsdiscriminated-union

How to declare multiple Literals with only one Literal attribute in F#?


I am trying to find an elegant way of assigning keys to symbols without having to do something like the following.

let [<Literal>] North = ConsoleKey.UpArrow // etc.

I'd rather do something like this, using only one attribute. Is there any way I can do that?

[<Literal>]
type Direction =
    | North of ConsoleKey.UpArrow
    | East of ConsoleKey.RightArrow
    | South of ConsoleKey.DownArrow
    | West of ConsoleKey.LeftArrow

Solution

  • Assuming your aim is to use these in a pattern match, here is one way to do it:

    // Use a type alias to shorten the name for ConsoleKey
    type Key = ConsoleKey
    
    // Create a general purpose active pattern that simply tests for equality
    let (|Is|_|) a b = if a = b then Some () else None
    
    // This is how you would use it
    let describeMovement key =
        match key with
        | Is Key.UpArrow -> "up"
        | Is Key.RightArrow -> "right"
        | Is Key.DownArrow -> "down"
        | Is Key.LeftArrow -> "left"
        | _ -> "invalid"