Variadic arguments, using Type Families instead of Multi-param Typeclasses

橙三吉。 提交于 2019-12-11 06:49:34

问题


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?


回答1:


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.



来源:https://stackoverflow.com/questions/8031320/variadic-arguments-using-type-families-instead-of-multi-param-typeclasses

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!