Я медленно работал над переносом пакета llvm, чтобы использовать типы данных, типы семейств и типы-натов и сталкивался с незначительной проблемой при попытке удалите два новых типа, используемые для классификации значений (ConstValue и Value), введя новый тип Value, параметризованный его константой.
 CallArgs принимает только аргументы Value 'Variable a и предоставляет функцию для приведения a Value 'Const a в Value 'Variable a. Я хотел бы обобщить CallArgs, чтобы каждый аргумент был либо 'Const, либо 'Variable. Можно ли это кодировать так или иначе с помощью семейств типов? Я думаю, что это возможно с помощью fundeps.
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
data Const = Const | Variable
data Value (c :: Const) (a :: *)
type family CallArgs a :: * 
type instance CallArgs (a -> b) = forall (c :: Const) . Value c a -> CallArgs b
type instance CallArgs (IO a)   = IO (Value 'Variable a)
... который не скомпилируется:
/tmp/blah.hs:10:1:
    Illegal polymorphic or qualified type:
      forall (c :: Const). Value c a
    In the type instance declaration for `CallArgs'
Если следующее решение работает (эквивалентно устаревшему коду), но требует, чтобы пользователь использовал каждую константу Value:
type family CallArgs' a :: * 
type instance CallArgs' (a -> b) = Value 'Variable a -> CallArgs' b
type instance CallArgs' (IO a)   = IO (Value 'Variable a)
