Adding constant fields to F# discriminated unions
Asked Answered
P

3

9

Is it possible to add constant field values to F# discriminated unions?

Can I do something like this?

type Suit
  | Clubs("C")
  | Diamonds("D")
  | Hearts("H")
  | Spades("S")
  with
    override this.ToString() =
      // print out the letter associated with the specific item
  end

If I were writing a Java enum, I would add a private value to the constructor like so:

public enum Suit {
  CLUBS("C"),
  DIAMONDS("D"),
  HEARTS("H"),
  SPADES("S");

  private final String symbol;

  Suit(final String symbol) {
    this.symbol = symbol;
  }

  @Override
  public String toString() {
    return symbol;
  }
}
Proposition answered 30/4, 2012 at 12:39 Comment(0)
P
11

Just for completeness this is what is meant:

type Suit = 
  | Clubs
  | Diamonds
  | Hearts
  | Spades
  with
    override this.ToString() =
        match this with
        | Clubs -> "C"
        | Diamonds -> "D"
        | Hearts -> "H"
        | Spades -> "S"
Pinchbeck answered 30/4, 2012 at 13:3 Comment(0)
L
7

The closest thing to your requirement is F# enums:

type Suit =
    | Diamonds = 'D'
    | Clubs = 'C'
    | Hearts = 'H'
    | Spades = 'S'

let a = Suit.Spades.ToString("g");;
// val a : string = "Spades"

let b = Suit.Spades.ToString("d");; 
// val b : string = "S"

The problem with F# enums is non-exhaustive pattern matching. You have to use wildcard (_) as the last pattern when manipulating enums. Therefore, people tend to prefer discriminated unions and write explicit ToString function.

Another solution is to make a mapping between constructors and corresponding string values. This is helpful in case we need to add more constructors:

type SuitFactory() =
    static member Names = dict [ Clubs, "C"; 
                                 Diamonds, "D";
                                 Hearts, "H";
                                 Spades, "S" ]
and Suit = 
  | Clubs
  | Diamonds
  | Hearts
  | Spades
  with override x.ToString() = SuitFactory.Names.[x]
Loach answered 30/4, 2012 at 12:56 Comment(2)
The first example of how not pass through the FSI.Dressing
| Diamonds = 'D' -> | value1 = integer-literal1 'D' bad literall for F# 2.0 , F#2.0 bug?Dressing
H
1

Pretty sure you can't, but is trivial to write a function that pattern matches and then compose the two things

Hectoliter answered 30/4, 2012 at 12:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.