Question

Here's what I've got, expressed with MultiParamTypeClasses:

class ListResultMult r a where
  lstM :: a -> [a] -> r

listM :: ListResultMult r a => a -> r
listM a = lstM a []


instance ListResultMult r a => ListResultMult (a -> r) a where
  lstM a as x = lstM x $ a:as

instance ListResultMult [a] a where
  lstM a as = reverse $ a:as

instance Show a => ListResultMult (IO ()) a where
  lstM a as = print . reverse $ a:as

Here's what I tried, using TypeFamilies (TypeSynonymInstances didn't help):

class ListResultFam r where
  type Elem r :: *
  lstF :: Elem r -> [Elem r] -> r

listFam :: ListResultFam r => Elem r -> r
listFam a = lstF a []


-- Illegal type synonym family application in instance: Elem r -> r
-- in the instance declaration for `ListResultFam (Elem r -> r)'
instance ListResultFam r => ListResultFam (Elem r -> r) where
  type Elem (Elem r -> r) = Elem r
  lstF a as x = lstF x $ a:as

instance ListResultFam [a] where
  type Elem [a] = a
  lstF a as = reverse $ a:as

Is there any way to accomplish this with Type Families? Why is this an "illegal" type synonym family application?

Was it helpful?

Solution

Type families aren't a replacement for multi param type classes, rather they replace functional dependencies.

This is because type families allow a mapping from one type to another, which is similar to what functional dependencies do with multi param type classes. Ie:

class Collection col e | col -> e where
   getHead :: col -> e

instance Collection [a] a where
   getHead = head

can be represented with type families as:

class Collection col where
  type CollectionHead col :: *
  getHead :: col -> CollectionHead col

instance Collection [a] where
   type CollectionHead [a] = a
   getHead = head

However they cannot replace a multi param type class without functional dependencies. Eg

class Converter a b where
  convert :: a -> b

instance Converter Int String where
  convert = show

instance Converter Int [Int] where
  convert x = [x]

Cannot be done by removing the b param and using type families. You could do something like this:

class Converter a where
   type Target a :: *
   convert :: a -> Target a

instance Converter Int where
   type Target Int = String
   convert = show

However it isn't possible to write the second instance, as it require a duplicate instance Converter Int.


With regards to your program, you can see instantly that there are no functional dependencies, just multiple parameter type classes. You therefor cannot do a straight conversion to type families with this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top