Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type class problem concerning "FlexibleInstances"

Given the type class

class Dictionary w where
  insert :: String -> String -> w -> w
  remove :: String -> w -> w
  lookUp :: String -> w ->  String

I can't write

instance Dictionary [(String,String)] where
  insert key value dic = (key,value) : remove key dic
  remove key dic = filter (\entry -> (fst entry) /= key) dic
  lookUp key [] = "not found"
  lookUp key ((k,v):xs) | k == key = v
                        | otherwise = lookUp key xs 

because of

Illegal instance declaration for `Dictionary[(String, String)]'
    (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 `Dictionary[(String, String)]'

... which I don't quite understand. Something like this works:

newtype Dic = Dic [(String,String)]

instance Dictionary Dic where
  insert key value (Dic dic) = Dic $ (key,value) : filter (\entry -> (fst entry) /= key) dic
  remove key (Dic dic) = Dic $ filter (\entry -> (fst entry) /= key) dic
  lookUp key (Dic []) = "not found"
  lookUp key (Dic ((k,v):xs)) | k == key = v
                              | otherwise = lookUp key (Dic xs)  

Is there a better way? Or should I use the suggested compiler directive?

like image 717
Landei Avatar asked Jan 28 '11 09:01

Landei


2 Answers

The reason is simple. Haskell 98 only allows instances for "unsaturated" types, this is types that are not fixed in their type variables. Read the error message it gives carefully, it exactly describes what the compiler wants to have.

To do what you want, there are basically the two way you already tried:

  • Switch on FlexibleInstances. This is the most common way, as this extension is one of the most used.
  • Wrap it into a newtype. Gives compatibility but is ugly.

Choose one ;)

like image 186
fuz Avatar answered Oct 24 '22 04:10

fuz


You can use pragma of form {-# LANGUAGE FlexibleInstances #-} instead of compiler directive. Scope of such pragma is limited to a single module.

like image 29
Boris Berkgaut Avatar answered Oct 24 '22 06:10

Boris Berkgaut