Вдохновленный вопросом о полиморфной функции между АТД, я пытаюсь создать изоморфизмы между несколькими (а не только двумя) типами, поэтому что каждый раз, когда мне нужен изоморфный, но не такой же тип, я могу посыпать свой код каким-нибудь convert
.
Предположим, у меня есть 3 ADT:
data AB = A | B deriving (Show)
data CD = C | D deriving (Show)
data EF = E | F deriving (Show)
Используя lens
, я могу реализовать 2 изоморфизма между AB и CD, CD и EF:
{-# LANGUAGE MultiParamTypeClasses #-}
class Isomorphic a b where
convert :: Iso' a b
instance Isomorphic AB CD where
convert = iso ab2cd cd2ab
where ab2cd A = C
ab2cd B = D
cd2ab C = A
cd2ab D = B
instance Isomorphic AB EF where
convert = iso ab2ef ef2ab
where ab2ef A = E
ab2ef B = F
ef2ab E = A
ef2ab F = B
Преобразовать A
в E
легко: A^.convert :: EF
. Преобразовать D
в B
также легко: D^.from convert :: AB
. Но если я хочу преобразовать из C
в E
через A
, я должен аннотировать типы для каждого промежуточного преобразования:
(C^.from convert :: AB)^.convert :: EF
Я понимаю, почему компилятор не может вывести промежуточные типы. Возможно, существует несколько изоморфизмов, посредством которых можно перейти от C
к E
. Но могу ли я упростить свой код, чтобы не аннотировать типы вручную везде?
Я мог бы просто написать еще один экземпляр для прямого преобразования между CD
и EF
, но что, если у меня больше трех типов? Если бы у меня было 5 изоморфных типов, мне пришлось бы указать 10 экземпляров, потому что количество изоморфных изображений между изоморфными объектами — это количество ребер в полном графе, который представляет собой треугольное число. Я бы предпочел указать n-1
экземпляров с компромиссом: я напишу больше convert
или from convert
.
Существует ли идиоматический способ установить изоморфизм между несколькими типами с помощью Iso
< /a> из lens
, чтобы было как можно меньше шаблонов и мне не нужно было все печатать и комментировать? Если мне нужно использовать для этого TemplateHaskell, как мне это сделать?
Мотивация в том, что в моей работе много до смешного сложных, но глупых типов, где () -> (() -> ()) -> X
и ((), X)
изоморфны X
. Мне приходится вручную оборачивать и разворачивать все, и мне нужен полиморфный способ свести сложные типы к более простым изоморфным типам.
Data.Coerce
не очень полезен для этого. - person jberryman   schedule 09.09.2016