Haskell: instances parameterized type one single type

Viewed 109

I'm writing some parser code, which involves a parameterized type:

data Power i    = Power1 { charges :: i } | Power2 { charges :: i }

Where I know the type i will always be an Int (but is parameterized because I need it for another type class).
Now I want to make my Power type derive from Show (in a specific formatting, so I need to override it myself). As I know that i will only ever be Int, I tried:

instance Show (Power Int) where
    show (Power1 0)    = ""
    show (Power1 i)    = "some formatting involving i\n"
    show (Power2 0)    = ""
    show (Power2 i)    = "some other formatting involving i\n"

However, this won't compile, with the message

    • Illegal instance declaration for ‘Show (Power Int)’
        (All instance types must be of the form (T a1 ... an)
         where a1 ... an are *distinct type variables*,
         and each type variable appears at most once in the instance head.
         Use FlexibleInstances if you want to disable this.)
    • In the instance declaration for ‘Show (Power Int)’
   |
22 | instance Show (Power Int) where

Why isn't this possible?

Why is this so different to the compiler than?

instance (Show i) => Show (Power i) where
2 Answers

GHC says All instance types must be of the form (T a1 ... an) where a1 ... an are *distinct type variables*. That is defined in Haskell 98. To take data type with a concrete type as class parameter require FlexibleInstances extension. Because there is overwrapping instances problem.

For example:

newtype Foo a = Foo a

class Bar a where
    baz :: a -> a

instance Bar (Foo Int) where
    baz = ...

instance Show a => Bar (Foo a) where
    baz = ...

When you call baz 1, compiler confuses whether version should call. 1 is Int but also belongs Show class! Details written in this post, you should read it when you have time.

You can not use type constraints with Types, but with Type classes. In your example, it is possible to instantiate Show for the Integral type class. Then show is defined for Power Int and Power Integer.

instance Integral a => Show (Power a) where
    show (Power1 0)    = ""
    show (Power1 i)    = "some formatting involving i\n"
    show (Power2 0)    = ""
    show (Power2 i)    = "some other formatting involving i\n"
Related