11
I've been slowly working on porting the llvm package to use data kinds, type families and type-nats and ran into a minor issue when trying to remove the two newtypes used for classifying values (ConstValue and Value) by introducing a new Value type parameterized by its constness.
CallArgs only accepts Value 'Variable a arguments and provides a function for casting a Value 'Const a to a Value 'Variable a. I'd like to generalize CallArgs to allow each argument to be either 'Const or 'Variable. Is this possible to encode this somehow using type families? I think it's probably doable with 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)
... which fails to compile:
/tmp/blah.hs:10:1:
Illegal polymorphic or qualified type:
forall (c :: Const). Value c a
In the type instance declaration for `CallArgs'
Where the following solution works (equivalent to the legacy code), but requires the user to cast the each constant Value:
type family CallArgs' a :: *
type instance CallArgs' (a -> b) = Value 'Variable a -> CallArgs' b
type instance CallArgs' (IO a) = IO (Value 'Variable a)