Вариативные аргументы, использующие семейства типов вместо многопараметрических классов типов - PullRequest
1 голос
/ 07 ноября 2011

Вот что я получил, выраженный в 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

Вот что я попробовал, используя TypeFamilies (TypeSynonymInstances не помогли):

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

Есть ли способ сделать это с помощью семейства типов? Почему это приложение семейства синонимов "незаконного" типа?

1 Ответ

8 голосов
/ 07 ноября 2011

Семейства типов не заменяют многопараметрические классы типов, а заменяют функциональные зависимости.

Это потому, что семейства типов позволяют отображать один тип в другой, что аналогично тому, что функциональные зависимости делают с классами многопараметрических типов.Т.е.:

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

instance Collection [a] a where
   getHead = head

можно представить с семействами типов как:

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

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

Однако они не могут заменить класс типов с несколькими параметрами без функциональных зависимостей.Например,

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

instance Converter Int String where
  convert = show

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

Невозможно сделать, удалив параметр b и используя семейства типов.Вы можете сделать что-то вроде этого:

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

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

Однако написать второй экземпляр невозможно, так как для него требуется дубликат Converter Int.


Что касается вашей программы, вы можете сразу увидеть, что нет никаких функциональных зависимостей, только несколько классов типов параметров.Поэтому вы не можете выполнить прямое преобразование в семейства типов с этим.

...