Только на платформе Haskell существует несколько универсальных библиотек с многочисленными перекрывающимися модулями (syb
., Data.Typeable
, Data.Data
,GHC.Generics
), но у меня возникли проблемы с очень простой общей задачей программирования.
Я хочу иметь возможность конвертировать между типами одной и той же формы, т.е. мне нужна полиморфная, типизированная функция преобразования между изоморфными типами, по сути то, что предлагается в конце этой статьи(PDF ), где упоминаются семейства индексированных типов.
Меня не интересует отказ от моего шаблона, а скорее возможность создавать новые библиотеки на основе абстракций суммы и произведения.
Вопрос ниже относится к GHC.Generic
, который, по моему мнению, был ближе всего к тому, что мне нужно, но приветствуются и другие решения.
Следующие два типа имеют одинаковую форму
data Pair = Pair Char Int deriving (Generic, Show)
data Pair2 = Pair2 Char Int deriving (Generic, Show)
Я хочу преобразовать значения между ними, используя GHC.Generics. Следующее не проходит проверку типов из-за всех фантомных параметров и прочей чепухи:
f :: Pair -> Pair2
f = to. from
В конечном итоге мне нужна функция, похожая на fromInteger
, которая имеет полиморфное возвращаемое значение для любогоGeneric
(или любой другой класс, который может поддерживать этот экземпляр ). Думаю, я ищу что-то вродеGHC.Generics
:
--class:
type family NormalForm a
class ToGeneric a where
to :: a -> NormalForm a
class FromGeneric b where
from :: NormalForm b -> b
--examples:
data A = A Char Int deriving Show
data B = B Char Int deriving Show
type instance NormalForm A = (Char,Int)
instance ToGeneric A where
to (A a b) = (a,b)
instance FromGeneric A where
from (a,b) = A a b
type instance NormalForm B = (Char,Int)
instance ToGeneric B where
to (B a b) = (a,b)
instance FromGeneric B where
from (a,b) = B a b
-- the function I'm looking for
coerce :: (ToGeneric a, FromGeneric b, NormalForm a ~ NormalForm b)=> a -> b
coerce = from. to
С вышеперечисленным мы можем делать все, что захочу:
*Main> (coerce $A 'a' 1) :: B
B 'a' 1
*Main> (coerce $A 'a' 1) :: A
A 'a' 1
РЕДАКТИРОВАТЬ:Вот как на самом деле работает функция Натана Хауэлла f
.
Возможно ли это сделать с библиотеками, которые в настоящее время находятся на платформе haskell?
Если нет, можно ли определить библиотеку, которая использует существующий механизм deriving
для Generic
, Data
и т. д., не прибегая к TH?