Reputation: 76
I have the code:
data Value = A|Two|Three...Ten|J|Q|K deriving (Eq, Ord, Enum)
instance Show Value where
show A = "A"
show Two = "2"
....
show K = "K"
And another data Suite
with a similar Show
instance for Hearts
, Spades
, Clubs
, and Diamonds
.
If I have
type Card = (Value, Suite)
Is it possible to create a show function that would transform (A, Spades)
into the string "AS"
?
Upvotes: 4
Views: 938
Reputation: 22596
To define an instance for type
you need to use the TypeSynonymInstances
extension. In your case instace Show Card
would be equivalent to instance Show (Card, Suite)
. This is not allowed without the FlexibleInstance
because standard type classes only allow instance of things like Show (a,b)
.
Now, using FlexibleInstance
wouldn't be enough because Show (a,b)
is already defined and your new instance will overlaps with the default one.
How does the compiler chose between your instance of Show (Card, Value)
and the standard one for Show (a,b)
? (Using a type is not enough as a type is like doing text substitution.)
To solve the problem of overlapping instance you need to use the OverlappingInstance
extension. This is a bit tricky and usually not recommended.
Upvotes: 3
Reputation: 1741
You should define a newtype
(or data
type) for Card
, the write the Show
instance for it.
newtype Card = Card (Value,Suite)
instance Show Card where
show (Card (v,s)) = show v ++ show s
You could also enable TypeSynonymInstances
and write the instance for Card
as you wrote it.
Edit: I should probably also mention that a type synonym is not the idiomatic/Haskell-ish way to handle your situation. A Card
is semantically different from a pair of Value
and Suite
, which could represent (for example) some initial condition in a card game, and not necessarily an actual card.
Upvotes: 6
Reputation: 30746
You probably ought to define your own data type instead of using (,)
.
data Card = Card Value Suite
instance Show Card where
show (Card v s) = show v ++ show s
Upvotes: 5