Существует несколько универсальных библиотек с многочисленными перекрывающимися модулями только на платформе 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. Ниже приведено описание typecheck из-за всех параметров phantom и других нонсенсов:
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
EDIT: Вот как работает функция Натана Хауэлла f
.
Вопросы
-
Возможно ли это сделать с библиотеками, находящимися в настоящее время на платформе haskell?
-
Если нет, можно ли определить библиотеку, которая использовала существующий механизм
deriving
дляGeneric
,Data
и т.д., не прибегая к TH?