Given:
data Foo = FooString String … class Fooable a where --(is this a good way to name this?) toFoo :: a -> Foo
I want to make String
an instance of Fooable
:
instance Fooable String where toFoo = FooString
GHC then complains:
Illegal instance declaration for `Fooable String' (All instance types must be of the form (T t1 ... tn) where T is not a synonym. Use -XTypeSynonymInstances if you want to disable this.) In the instance declaration for `Fooable String'
If instead I use [Char]
:
instance Fooable [Char] where toFoo = FooString
GHC complains:
Illegal instance declaration for `Fooable [Char]' (All instance types must be of the form (T a1 ... an) where a1 ... an are type *variables*, and each type variable appears at most once in the instance head. Use -XFlexibleInstances if you want to disable this.) In the instance declaration for `Fooable [Char]'
Question:
This is because String
is just a type alias for [Char]
, which is just the application of the type constructor []
on the type Char
, so this would be of the form ([] Char)
. which is not of the form (T a1 .. an)
because Char
is not a type variable.
The reason for this restriction is to prevent overlapping instances. For example, let's say you had an instance Fooable [Char]
, and then someone later came along and defined an instance Fooable [a]
. Now the compiler won't be able to figure out which one you wanted to use, and will give you an error.
By using -XFlexibleInstances
, you're basically promising to the compiler that you won't define any such instances.
Depending on what you're trying to accomplish, it might be better to define a wrapper:
newtype Wrapper = Wrapper String instance Fooable Wrapper where ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With