Adding constant fields to F# discriminated unions
-
04-06-2021 - |
سؤال
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;
}
}
المحلول
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"
نصائح أخرى
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]
Pretty sure you can't, but is trivial to write a function that pattern matches and then compose the two things