Variadic arguments using Type Families instead of Multi-param Typeclasses

Here is what I got expressed using MultiParamTypeClasses:

class ListResultMult ra where lstM :: a -> [a] -> r listM :: ListResultMult ra => a -> r listM a = lstM a [] instance ListResultMult ra => 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 is what I tried using TypeFamilies (TypeSynonymInstances did not 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 a way to do this using type families? Why is this an β€œillegal” family type synonym app?

+1
source share
1 answer

Family types are not a substitute for multi-parameter classes, instead of replacing functional dependencies.

This is due to the fact that type families can be mapped from one type to another, which is similar to what functional dependencies are performed with classes with several parameters. I.e:

 class Collection col e | col -> e where getHead :: col -> e instance Collection [a] a where getHead = head 

can be represented by 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 class with several parameters without functional dependencies. For instance,

 class Converter ab where convert :: a -> b instance Converter Int String where convert = show instance Converter Int [Int] where convert x = [x] 

Cannot delete parameter b and use type families. You can 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 is not possible to record a second instance, since it requires a duplicate of an instance of Converter Int .


As for your program, you can immediately see that there are no functional dependencies, just a few classes of parameter types. Thus, you cannot do a direct conversion for the type of families with this.

+8
source

Source: https://habr.com/ru/post/900905/


All Articles