Markeazy
Markeazy

Reputation: 76

Is it possible to declare a typeclass instance for a type alias?

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

Answers (3)

mb14
mb14

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

Lazersmoke
Lazersmoke

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

Chris Martin
Chris Martin

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

Related Questions