Я медленно работал над переносом пакета 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)