Вдохновленный вопрос о полиморфной функции между ADT. Я пытаюсь создать изоморфизмы между несколькими (не только 2) типами, так что каждый раз, когда мне нужен изоморфный но не тот же тип, я могу посыпать свой код некоторым 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
, но что, если у меня есть более 3 типов? Если бы у меня было 5 изоморфных типов, мне пришлось бы указать 10 экземпляров, потому что число изосов между изоморфными объектами - это число ребер в полном графике, которое является треугольное число. Я бы предпочел указать экземпляры n-1
, с компромиссом, который я пишу больше convert
или from convert
.
Существует ли идиоматический способ установить изоморфизмы между несколькими типами, используя Iso
от lens
, чтобы было минимальное количество шаблонов и мне не нужно вводить все-аннотировать все? Если мне нужно использовать TemplateHaskell для этого, как мне это сделать?
Мотивация заключается в том, что в моей работе у меня много смехотворно сложных, но глупых типов, где () -> (() -> ()) -> X
и ((), X)
изоморфны X
. Я должен вручную обернуть и развернуть все, и я бы хотел, чтобы какой-то полиморфный способ уменьшить сложные типы до более простых изоморфных типов.