Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I not make String an instance of a typeclass?

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:

  • Why can I not make String and instance of a typeclass?
  • GHC seems willing to let me get away with this if I add an extra flag. Is this a good idea?
like image 215
John F. Miller Avatar asked May 09 '11 19:05

John F. Miller


1 Answers

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     ... 
like image 80
hammar Avatar answered Sep 22 '22 02:09

hammar