Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid explicit type signatures here?

class Listy a b where
   fromList :: [b] -> a
   toList :: a -> [b]
   lifted :: ([b] -> [b]) -> (a -> a) 
   lifted f = fromList . f . toList

data MyString = MyString { getString :: String } deriving Show

instance Listy MyString Char where
  toList = getString
  fromList = MyString

Now I need to write e.g. lifted (reverse::(String -> String)) (MyString "Foobar"). Is there a trick to avoid the need for the type signatures?

like image 379
Landei Avatar asked Oct 17 '12 07:10

Landei


2 Answers

Essentially the problem is that setting the type of a does not tell the compiler what the type of b is. You might think that since there is only one instance of the class (where a is MyString and b is Char), but anybody can add new instances at any time. So the fact that there's only one instance now doesn't help the compiler decide what types you want.

The solution to this is either to use Functional Dependencies, or Type Families. The latter is the newer solution and is intended to eventually "replace" the former, but right now both are still fully supported. Whether FDs ever go away remains to be seen. Anyway, with FDs:

class Listy a b | a -> b where ...

Essentially this says "there can only ever be one class instance for each a". In other words, once you know a, you can always determine b. (But not the reverse.) The rest of the class looks like it did before.

The alternative is TFs:

class Listy a where
  type Element a :: *
  ...

instance Listy MyString where
  type Element MyString = Char
  ...

Now instead of the second type being called b, it's called Element a. The word Element acts like a class method that takes a listy type and returns the corresponding element type. You can then do

instance Listy ByteString where
  type Element ByteString = Word8
  ...

instance Listy [x] where
  type Element [x] = x
  ...

instance Ord x => Listy (Set x) where
  type Element (Set x) = x
  ...

and so on. (Not that Listy necessarily makes sense for all the types above; these are just examples of how to define the class.)

like image 121
MathematicalOrchid Avatar answered Oct 24 '22 16:10

MathematicalOrchid


You can try -XFunctionalDependencies

class Listy a b | a -> b where
   fromList :: [b] -> a
   toList :: a -> [b]
   lifted :: ([b] -> [b]) -> (a -> a) 
   lifted f = fromList . f . toList
like image 22
Yuras Avatar answered Oct 24 '22 14:10

Yuras