Here's a hacky solution with some extra typing, but without backticks! I first posted this on reddit, if that's okay.
I assume you have derived Enum
for Rank
.
data OF = OF
ace :: OF -> Suit -> PokerCard
ace _ s = PokerCard Ace s
-- or point-free
two :: OF -> Suit -> PokerCard
two _ = PokerCard Two
-- or with const
three :: OF -> Suit -> PokerCard
three = const (PokerCard Three)
-- you get the idea!
-- the rest in one line:
four,five,six,seven,eight,nine,ten,jack,king :: OF -> Suit -> PokerCard
[four,five,six,seven,eight,nine,ten,jack,king] = map (const . PokerCard) [Four .. King]
-- now you can write
pokerDeck = [
ace OF Spades, two OF Spades -- and so on
]
The OF datatype isn't strictly necessary, but prevents confusing (but very metal) stuff like ace "Motorhead" Spades
. You can still write ace undefined Spades
, there's really no way around that, I think.
If of
wasn't a keyword, you could even write of = OF
.
There is also an utterly evil hack to get rid of the 'of' entirely, and using numbers for cards:
{-# LANGUAGE FlexibleInstances #-} -- this goes on top of your file
instance Num (Rank -> Suit) where
fromInteger n = (undefined : map Card[Ace .. King]) !! (fromInteger n)
Now 2 Spades :: Card
typechecks (but you need the explicit type!) and is what you think it is :-) However, I strongly advise you to not do this in serious code; but it looks kind of cool.