Вы могли бы втянуть свой GADT в этот:
data HList t where
Empty :: t ~ '[] => HList t
Cons :: t ~ (a ': b) => a -> HList b -> HList t
Это больше не «настоящий» GADT, поскольку каждый конструктор возвращает общий тип HList t
, как это происходит в простых старых алгебраических типах данных.
Хитрость в том, что переменная типа t
выглядит непринужденной в типе результата HList t
, но фактически ограничена ограничениями на равенство типов t ~ ...
, поэтому для получения той же семантики, что и у исходного типа.
Если вы хотите полностью удалить синтаксис GADT, вы можете сделать следующее. Вам все еще нужно будет включить некоторые расширения, чтобы использовать ограничения ~
.
{-# LANGUAGE DataKinds, TypeOperators, TypeFamilies, ExistentialQuantification #-}
data HList2 t
= t ~ '[] => Empty2
| forall a b . t ~ (a ': b) => Cons2 a (HList2 b)
В упомянутой вами статье, вероятно, указывается, что, поскольку t
участвует в ограничениях равенства, он играет номинальную роль.