Why can't I make String an instance of a class?

Considering

data Foo = FooString String … class Fooable a where --(is this a good way to name this?) toFoo :: a -> Foo 

I want to make a String instance 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't I create a String and an instance of a class?
  • The GHC seems to want me to get away with adding an extra flag. Is that a good idea?
+78
type-systems haskell ghc typeclass
May 9 '11 at 19:45
source share
4 answers

This is because String is just a type alias for [Char] , which is just a constructor application of type [] for type Char , so it will look like ([] Char) . which has no form (T a1 .. an) , because Char not a type variable.

The reason for this limitation is to prevent duplicate instances. For example, suppose you have instance Fooable [Char] , and then someone later instance Fooable [a] up and defines instance Fooable [a] . Now the compiler will not be able to determine which one you want to use, and you will receive an error message.

Using -XFlexibleInstances , you basically promise the compiler that you will not define such instances.

Depending on what you are trying to execute, it is better to define a shell:

 newtype Wrapper = Wrapper String instance Fooable Wrapper where ... 
+56
May 09 '11 at 19:52
source share

You use the two limitations of the Haskell98 classic classes:

  • they prohibit type synonyms in cases
  • they prohibit nested types, which, in turn, do not contain type variables.

These onerous restrictions are removed by two language extensions:

  • -XTypeSynonymInstances

which allows the use of synonyms of the type (for example, String for [Char] ) and:

  • -XFlexibleInstances

which remove restrictions on instance types of the form T ab .. , where the parameters are type variables. The -XFlexibleInstances flag allows the instance declaration header to specify arbitrary nested types.

Note that removing these restrictions sometimes leads to overlapping instances , in which case an additional language extension may be required to resolve the ambiguity, allowing the GHC to choose the instance for you.




Literature::

+17
May 09 '11 at 19:52
source share

FlexibleInstances are not a good answer in most cases. Better alternatives wrap String in newtype or introduce a helper class as follows:

 class Element a where listToFoo :: [a] -> Foo instance Element Char where listToFoo = FooString instance Element a => Fooable [a] where toFoo = listToFoo 

See also: http://www.haskell.org/haskellwiki/List_instance

+4
Mar 03 '13 at 19:55
source share

Adding to these answers, if you are uncomfortable with removing restrictions, there may be times when it makes sense to wrap your String in newtype, which may be an instance of the class. A compromise would be a potential ugliness that would have to be wrapped and deployed in your code.

+2
May 10 '11 at 8:32 a.m.
source share



All Articles