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
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.