Действительно ли этот GADT имеет представление о роли типа

Этот тип данных может иметь type role HCons' representational representational, что позволяет использовать coerce для добавления или удаления новых типов, применяемых к элементам, без необходимости перебирать список.

data HNil' = HNil'
data HCons' a b = HCons' a b

Однако синтаксис этих списков не так хорош, как те, у которых есть следующий GADT

data HList (l::[*]) where
    HNil  :: HList '[]
    HCons :: e -> HList l -> HList (e ': l)

У меня есть класс для конвертировать между этими двумя представлениями, например Prime (HList [a,b]) ~ HCons' a (HCons' b HNil'). Создает ли этот класс

coerceHList :: Coercible (Prime a) (Prime b) => HList a -> HList b
coerceHList = unsafeCoerce

безопасно?

Ответы

Ответ 1

Я не думаю, что само существование конверсии достаточно. Например, следующее также позволяет мне конвертировать между GADT и коэрцитивной парой типов, но, конечно, было бы небезопасно напрямую принуждать GADT:

newtype Age = Age Int

data Foo a where
   I :: Bool -> Int -> Foo Int
   A :: Age -> Bool -> Foo Age

class ConvFoo a where
   toFoo :: (Bool, a) -> Foo a
   fromFoo :: Foo a -> (Bool, a)

instance ConvFoo Int where
   toFoo (b, i) = I b i
   fromFoo (I b i) = (b, i)

instance ConvFoo Age where
   toFoo (b, a) = A a b
   fromFoo (A a b) = (b, a)

Я мог бы также тривиально определить функцию типа UnFoo, похожую на Prime.

Я думаю, что ключевое различие между двумя примерами заключается в том, что в моем случае Age и Int имеют одинаковое представление, тогда как в ваших '[] и e':l не имеют того же представления.

Итак, есть еще аргумент для высказывания, как вы предлагаете в заголовке, что l имеет репрезентативную роль типа, потому что очевидно, что HList l1 и HList l2 имеют те же представления, если l1 и l2 имеют одинаковые представления.

Однако, поскольку в теории представления зависят от реализации, я не думаю, что вы можете когда-либо считать это абсолютно безопасным, пока GHC не примет его напрямую.